zoukankan      html  css  js  c++  java
  • 关于this的全面解析(call,apply,new)

    我们在写代码的时候,时常会被this弄的傻傻分不清楚,看源码的时候也经常被call啊apply啊弄的头皮发麻。this到底是什么?本文主要根据书上和实际应用做了一些归纳。一般情况下this有4种绑定规则:

    1、默认绑定 - this指向全局变量

    举例:

           function baz(){
               console.log('a',this.a);
           };
           var a = 2; 
           baz();
    
          // a 2
    

    在非严格模式下,我们调用了baz,它没有被任何对象包裹,而是暴露在全局环境中,因此此时它被调用的上下文就是全局环境,所以获取到this.a是2;

    2、隐式绑定

    这种情况应该是最常见的,我们调用的方法被包含在某个对象中,此时应该找到调用这个方法的对象所处的上下文。
    举例:

           function baz(){
             console.log('a',this.a);
           };
           var a = 2;
           var obj = {
               a: 3,
               baz: baz
           }
           obj.baz();
           
           // a, 3
    

    这个时候,this指向调用baz这个方法的对象obj;所以获取的this.a就是obj.a是3;
    思考一下下面的this.a的值又是什么:

          function baz(){
             console.log('a',this.a);
           };
           var a = 2;
           var obj = {
               a: 3,
               baz: baz
           };
    
           var obj2 = {
               a: 4,
               baz: obj.baz
           }
           obj2.baz();
    
    

    tips: 对象属性的引用链只有最后一层在调用位置中起作用。

    3、显式绑定

    这里就是函数可以使用的方法call(obj,param1,param2,...)apply(obj,[param1,param2,...]),它们的作用是我们可以显式的改变函数的上下文(this),参数说明:

    • obj:一个对象,将方法的this指向该对象的this;
    • paramX:参数,两者的表现形式不同
           var a = 2;
           function baz(){
             console.log('a',this.a);
           };
           
           var obj = {
               a: 3           
           };
    
           baz.call(obj); // 改变了this,并执行了函数
           // a 3
    

    如果直接baz(),则采用的是第一种规则,这里使用baz.call强行将baz的this指向了obj,所以此时baz中的this是obj;
    应用场景:带参数的

            var a = 2;
    
            function baz(p1, p2) {
                console.log(this.a, p1, p2);
            };
    
            var obj = {
                a: 3
            };
    
            var foo = function () {
                return baz.apply(obj, arguments)
            };
    
            foo("hi,", "heimayu");
    
            // 3 hi, heimayu
    

    4、new绑定

    在js中,我们经常使用new来对函数进行构造调用,如下:

           function Foo(a) {
                this.a = a;
            };
    
            var foo = new Foo(3);
            console.log("a", foo.a)
    

    这里,使用new Foo()的时候构造出一个新的对象foo并把它绑定到Foo调用中的this上。

    5、优先级

    在大多数情况下我们找到函数的调用位置,并判断应用哪种规则,就可以快速找到this;结论:
    new绑定 > 显式绑定(call,apply) > 隐式绑定 > 全局默认绑定

    6、一些例外

    规则是死的,程序是活的,总有例外出现。比如啊:
    我不关心this是什么

            function foo(a, b) {
                console.log("a:" + a, "b:" + b);
            };
    
            foo.apply(null, [1, 2]);
            // a:1 b:2
    

    ES6箭头函数
    箭头函数不使用上面的规则,而是根据 由外层的作用域来决定它的this

           function foo() {
                // return function () {
                //     console.log('第一种情况', this.a)
                // }
                return (a)=>{
                    console.log('第二种情况',this.a)
                }
            };
    
            var obj1 = {
                a: 2
            };
    
            var obj2 = {
                a: 3
            };
    
            var bar = foo.call(obj1);
            bar.call(obj2);
            // 第一种情况:3
            // 第二种情况:2
    

    记住箭头函数的绑定无法被修改!!!因此在执行bar的时调用了foo,而foo中的this是指向到obj1的。
    最常见的场景:

            var a = 1;
            var obj = {
                a:2,
                foo: function(){
                    setTimeout(function(){
                        console.log(this.a)
                    },100)
                }
            };
    
            obj.foo();
            // 1
    

    在ES5中,我们想打出的值是2,会这样做:

            var a = 1;
            var obj = {
                a:2,
                foo: function(){
                    let self = this;
                    setTimeout(function(){
                        console.log(self.a)
                    },100)
                }
            };
    
            obj.foo();
    

    在ES6中,则可以直接这样:

            var a = 1;
            var obj = {
                a:2,
                foo: function(){
                    setTimeout(()=>{
                        console.log(this.a)
                    },100)
                }
            };
    
            obj.foo();
    

    理解一下:因为箭头函数中的this,指向了foo,foo的上下文是obj。具体的说:箭头函数会继承外层函数调用的this绑定

  • 相关阅读:
    CSS知识点总结(一)
    HTML知识点总结(二)
    HTML/CSS 基础知识总结(一)
    Nodejs 发送邮件
    Nodejs 发送短信验证码
    Nodejs 上传下载功能的实现(同步)
    Nodejs报错集
    Nodejs的安装及配置
    nodejs+bootstrap实现分页效果
    切换Mac默认PHP版本为MAMP
  • 原文地址:https://www.cnblogs.com/webhmy/p/10212597.html
Copyright © 2011-2022 走看看