Nodejs MDN上面的Function.prototype.bind中的这一句该怎么理解?
Nodejs MDN上面的Function.prototype.bind中的这一句该怎么理解?
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== “function”) {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError(“Function.prototype.bind - what is trying to be bound is not callable”);
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
原文在这里:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
12行的this instanceof fNOP && oThis
中,什么情况下bind中的this才会是fNOP的instance?
看上去好像是用来区分是不是在new fBound
(对oThis参数的说明:The value is ignored if the bound function is constructed using the new operator.),但是&& oThis
之后逻辑又看起来很奇怪。
这里的判断该如何理解?
当然,我们来详细解析一下 this instanceof fNOP && oThis
这一行代码。这行代码用于处理 bind
函数在不同调用方式下的行为,特别是在使用 new
关键字时。
解析
-
this instanceof fNOP
:这部分检查当前调用fBound
的上下文是否为fNOP
的实例。fNOP
是一个空构造函数,其原型被设置为this.prototype
,即原函数的原型。如果fBound
被用作构造函数(即使用new
关键字),那么它的this
将指向一个新创建的对象,并且这个对象的原型链会继承自fNOP
。 -
&& oThis
:这部分确保只有当fBound
作为构造函数使用时,oThis
参数才有效。如果fBound
不是作为构造函数使用,则oThis
会被忽略。
示例代码
让我们通过一个例子来更好地理解这一点:
function greet(name) {
console.log(`Hello, ${name}`);
}
// 使用 bind 绑定 this 到一个特定对象
const boundGreet = greet.bind({ name: 'Alice' });
// 正常调用
boundGreet(); // 输出: Hello, Alice
// 使用 new 创建一个新的对象
const BoundGreetConstructor = greet.bind({ name: 'Bob' });
const instance = new BoundGreetConstructor('Charlie');
console.log(instance.name); // 输出: Bob
详细解释
-
在第一种情况中,
boundGreet
是通过.bind
方法绑定到{ name: 'Alice' }
的,因此调用boundGreet()
时,this
指向{ name: 'Alice' }
。 -
在第二种情况中,我们创建了一个新的构造函数
BoundGreetConstructor
,它使用.bind
方法绑定到{ name: 'Bob' }
。当我们使用new BoundGreetConstructor('Charlie')
来创建一个新实例时,this
会指向这个新创建的对象。此时,this instanceof fNOP
为true
,因为fNOP
的原型被设置为greet.prototype
。因此,fBound
返回的新对象会继承fNOP
的原型,而oThis
参数则被忽略。
总结
this instanceof fNOP && oThis
这一行代码确保了 bind
函数的行为符合预期,无论是直接调用还是作为构造函数使用。通过这种方式,bind
可以正确地处理 this
的绑定,无论是在普通函数调用还是构造函数调用的情况下。
bind返回的函数在作为构造函数的时候this instanceof fNOP会是true,否则就是false。
在Function.prototype.bind
实现中,第12行的条件this instanceof fNOP && oThis
用于处理使用new
操作符调用绑定函数的情况。具体来说:
this instanceof fNOP
检查当前的this
是否为fNOP
的实例。&& oThis
确保oThis
参数不为undefined
或null
。
这两部分结合起来是为了确保当fBound
被用作构造函数(即通过new
操作符调用时),this
指向的是新创建的对象实例,而不是oThis
。
示例代码
function foo(a, b) {
this.a = a;
this.b = b;
}
const boundFoo = foo.bind(null, 1);
// 使用 new 调用
const instance = new boundFoo(2);
console.log(instance.a); // 输出: 1
console.log(instance.b); // 输出: 2
// 直接调用
const result = boundFoo(2);
console.log(result); // 输出: undefined (因为foo没有返回值)
在这个例子中:
- 当通过
new boundFoo(2)
创建实例时,this
指向新创建的对象实例。 - 当直接调用
boundFoo(2)
时,this
指向null
,因此a
和b
属性会添加到全局对象(浏览器环境下的window
对象)上。
这样做的目的是为了确保当fBound
作为构造函数使用时,其内部的this
能够正确地指向新创建的对象实例。