美文网首页1000天日更计划
Day33:this的绑定规则

Day33:this的绑定规则

作者: 钱塘风华 | 来源:发表于2019-04-26 23:56 被阅读3次

    【书名】:你不知道的JavaScript(上卷)

    【作者】:Kyle Simpson

    【本书总页码】:213

    【已读页码】:106

    1. 默认绑定(独立函数调用时)

    非严格模式下,默认绑定到全局对象;严格模式下,全局对象将无法使用默认绑定,因此 this 会绑定到 undefined。

    2. 隐式绑定

    调用位置是否有上下文对象。

    function foo() {

        console.log( this.a );

    }

    var obj = {

        a: 2,

        foo: foo

    };

    obj.foo(); // 2,this指向obj

    对象属性引用链中只有最顶层或者说最后一层会影响调用位置。

    function foo() {

        console.log( this.a );

    }

    var obj2 = {

        a: 42,

        foo: foo

    };

    var obj1 = {

        a: 2,

        obj2: obj2

    };

    obj1.obj2.foo(); // 42 this指向的是obj2

    隐式绑定的特殊情况——隐式丢失

    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.foo 的一个引用,但是实际上,它引用的是 foo 函数本身,因此此时的bar() 其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

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

    function foo() {

        console.log( this.a );

    }

    function doFoo(fn) {

        // fn 其实引用的是 foo

        fn(); // <-- 调用位置!

    }

    var obj = {

        a: 2,

        foo: foo

    };

    var a = "oops, global"; // a 是全局对象的属性

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

    参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值,所以this隐式绑定隐式丢失。

    3. 显式绑定——call(..) 和 apply(..)

    它们的第一个参数是一个对象,它们会把这个对象绑定到this,接着在调用函数时指定这个 this。

    function foo() {

        console.log( this.a );

    }

    var obj = {

        a:2

     };

    foo.call( obj ); // 2 this显式绑定到obj

    如果传入了一个原始值(字符串类型、布尔类型或者数字类型)来当作 this 的绑定对象,这个原始值会被转换成它的对象形式(也就是new String(..)、new Boolean(..)或者new Number(..))。这通常被称为“装箱”。

    function foo () {

        console.log(this.toString());

    }

    foo.apply('hello'); // hello 

    显式绑定依然无法解决绑定丢失问题。

    3.1. 硬绑定解决绑定丢失

    function foo() {

        console.log( this.a );

    }

    var obj = {

        a:2

    };

    var bar = function() {

        foo.call( obj );

    };

    bar(); // 2

    setTimeout( bar, 100 ); // 2

    // 硬绑定的 bar 不可能再修改它的 this

    bar.call( window ); // 2

    硬绑定的典型应用场景就是创建一个包裹函数,传入所有的参数并返回接收到的所有值:

    另一种使用方法是创建一个可以重复使用的辅助函数:

    由于硬绑定是一种非常常用的模式,所以在 ES5 中提供了内置的方法 Function.prototype.bind,它的用法如下:

    bind(..) 会返回一个硬编码的新函数,它会把参数设置为 this 的上下文并调用原始函数。

    3.2. API调用的“上下文”

    第三方库的许多函数,以及 JavaScript 语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被称为“上下文”(context),其作用和 bind(..) 一样,确保你的回调函数使用指定的 this。

    这些函数实际上就是通过 call(..) 或者 apply(..) 实现了显式绑定。

    4. new绑定

    使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

    1. 创建(或者说构造)一个全新的对象。

    2. 这个新对象会被执行[[原型]]连接。

    3. 这个新对象会绑定到函数调用的this。

    4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

    使用 new 来调用 Foo(..) 时,会构造一个新对象并把它绑定到 Foo(..) 调用中的 this上。

    相关文章

      网友评论

        本文标题:Day33:this的绑定规则

        本文链接:https://www.haomeiwen.com/subject/sfvcnqtx.html