首页 > 代码库 > 深入理解this

深入理解this

            你可能听过很多this,就像C#中的this就是指向一个他的实例对象,

      但是在javascript中,我可能要告诉你,他是在运行时动态绑定的

他指向什么,完全取决于函数在哪里调用                                                                  

        在这里还要说明一个东西,调用栈----------->通俗的来讲,就是为了到达一个方法所调用的所有方法

    我们可以用浏览器自带的调试工具来查看

        function foo(){
            console.log(this.a);
        }
        var b={
            a:10,
            foo:foo
        };
        b.foo();//10

    从运行的结果,我们就可以看出来,当调用b.foo()时this被绑定到了b   技术分享

了解了调用栈以后,我们在来了解一个词,调用位置                                                                    

   调用位置,顾名思意,也就是我调用这个函数的上一个位置,也叫做调用位置0-0

        function foo(){
            console.log(this.a);
        }
        var a=20;
        foo();//20

技术分享

 

 仔细的人就会发现,上面的调用位置和下面的调用位置都是全局,那么是什么让他们产生了差异?

如果你仔细的看的话,就会发现他们的差别就在于调用foo()的方法不同,上面的是b.foo(),而下面的只是foo();

  也就是这一点的差异,让绑定发生的变化

为了说明这点我们需要指明绑定时的4个规则

1.默认绑定                                                                                                                        

        function foo(){
            console.log(this.a);
        }
        var a=20;
        foo();//20

独立函数调用。可以把这条规则看作是无法应用其他规则时的默认规则。

  在这里需要说明的是,只有在非严模式下,默认绑定才会绑定到全局,否则会报ReferencesError错误

2.隐式绑定                                                                                                                          

另一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含,不过这种说法可能会造成一些误导。

 我们就拿上面的那个例子来说

        function foo(){
            console.log(this.a);
        }
        var b={
            a:10,
            foo:foo
        };
        a=20;
        b.foo();//10
        foo();//20

在这个例子中,我们通过b.foo();来调用foo()函数,在这里需要注意的是b.foo只是对foo()函数的一个引用

那么你可能就会说既然只是一个引用,那么我调用它和直接调用它没有什么区别吧,但是,我们还记得第一个标题?

  this是在被调用时被绑定的!!!  而我们调用的地方正是b,所有this就指向了b!!!!!!!!!!!!

当然使用这种隐式绑定也有一定的缺点 !!!           请看下面的例子                                                   

        function foo(){
            console.log(this.a);
        }
        var b={
            a:10,
            foo:foo
        };
        a=20;
        var bar=b.foo;
        bar();//20 这里是20你想通了吗?
        

一种更微妙、更常见并且更出乎意料的情况发生在传入回调函数时                                                

        function foo(){
            console.log(this.a);
        }
        var b={
            a:10,
            foo:foo
        };
        a=20;
        function bind(fn){
            fn();
        }
        bind(b.foo);//20 在这里输出的是20 是因为b.foo 仅仅就是一个函数的引用,所以他调用了默认绑定,指向this

上面的例子和下面的结果一样

        function foo(){
            console.log(this.a);
        }
        var b={
            a:10,
            foo:foo
        };
        a=20;
        setTimeout(b.foo,1000);//20  可以看到结果和上面一样!!!!!!!!

3.显示绑定                                                                                                                         

  Call(this,参数)                                                                                                           

        var b1={
            a:10,
            foo:function foo(){
                console.log(this.a);
            }
        };
        var b2={a:20};
        
        b1.foo.call(b2);//20 在这里我们显示的让this指向了b2这个对象

  Apply(this,参数数组)                                                                                                   

        var b1={
            a:10,
            foo:function foo(t,e){
                console.log(this.a+t+e);
            }
        };
        var b2={a:20};
        
        b1.foo.apply(b2,[1,2]);//23  我们可以看到,他们除了在参数的传递上不同外,其他的都一样

bind                                                                                                           

        function foo(){
            console.log(this.a);
        }
        var a=200;
        var b={a:100};
        setTimeout(foo.bind(b)//100
        ,1000);

当然在这里有必要说一下bind的语法 function.bind(Object),也就是将一个对象绑定到一个函数上

4.New绑定                                                                                                                      

使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
  1. 创建(或者说构造)一个全新的对象。
  2. 这个新对象会被执行 [[ 原型 ]] 连接。
  3. 这个新对象会绑定到函数调用的 this 。
  4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象

function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2

那么有这4个绑定规则,哪个的优先权更高呢?---------------------->请看下章

深入理解this