js之this究竟指向谁?

来自《你不知道的JS》的学习

《=========================================================================》

1.在理解this的绑定过程之前,首先要理解调用位置:调用位置就是函数在代码中被调用的位置,而不是声明的位置。

寻找调用位置就是寻找“函数被调用的位置”。

function baz(){

    //当前调用栈是:baz

    //因此,当前调用位置是全局作用域

    console.log("baz");

    bar(); <==bar的调用位置

}

function bar(){

    //当前调用栈是baz->bar

    //因此,当前调用位置在baz中

    foo(); //<--foo的调用位置

}

function foo(){

    //当前调用栈是baz->bar->foo

    //所以,调用位置在bar中

    console.log("foo");

}

baz(); //<---baz的调用位置


2.this的绑定对象规则

  • 最常用的函数调用类型:独立函数调用

    function foo(){

        console.log(this.a);

    }

    var a=2;

    foo();//2

  • 隐式绑定:

    function foo(){   

        console.log(this.a); 

    }

    var obj2 = {

        a:42,

        foo:foo

    };

    var obj1 = {

        a=2,

       obj2:obj1

    };

    //对象属性引用链上只有上一层或者说最后一层在调用位置起作用。

    obj1.obj2.foo();//42

    (隐式丢失) function foo(){

        console.log(this.a);

    }

     var obj =  {

        a:2,

        foo:foo

    };

    var bar = obj.foo;//函数别名;

    var a = "oops,global";//a是全局变量的属性

    bar(); //"oops,global"

    虽然bar为obj.food的1个引用,但实际上它引用的依旧是foo函数本身,所以这时的bar()其实是一个不带任何修饰符的函数引用,所以默认绑定。别外,参数传递其实也是一种隐藏赋值,所以传入参数是也会被隐式赋值。

     function foo(){

        console.log(this.a);

    }

    function doFoo(fn){

        fn();

    }

     var obj =  {

        a:2,

        foo:foo <------调用位置

    };

    var bar = obj.foo;//函数别名;

    doFoo(obj.foo);//"oops,global"

  • 显示绑定(bind、apply,他们的第一个参数是一个对象,给this准备的)
  • new绑定

3.优先级

  • 函数是否在new中调用(new 绑定)?如果是的话this绑定的是新创建的对象。var bar = new foo();
  • 函数是否通过call、apply(显示绑定)或者硬绑定调用?如果是的话,this绑定的是指定对象。var bar = foo.call(obj2);
  • 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的那个上下文对象。var  bar =obj1.foo();
  • 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象。var bar = foo();

4.间接引用:这种情况下,调用这个函数会应用默认绑定规则。

    function foo(){

        console.log(this.a);

        var a=2;

        var o = {a:3,foo:foo};

        var p = {a:4};

        o.foo();//3

        (p.foo=o.foo())();//3

    }

    赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo()。根据之前我们说过,这里会应用默认绑定。


猜你喜欢

转载自blog.csdn.net/gzkahjl/article/details/80964805