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之后逻辑又看起来很奇怪。 这里的判断该如何理解?


3 回复

当然,我们来详细解析一下 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 fNOPtrue,因为 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参数不为undefinednull

这两部分结合起来是为了确保当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,因此ab属性会添加到全局对象(浏览器环境下的window对象)上。

这样做的目的是为了确保当fBound作为构造函数使用时,其内部的this能够正确地指向新创建的对象实例。

回到顶部