1000天日更计划

Day33:this的绑定规则

2019-04-26  本文已影响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上。

上一篇下一篇

猜你喜欢

热点阅读