问一个关于Javascript中bind函数在Nodejs中的问题

问一个关于Javascript中bind函数在Nodejs中的问题

先上代码

var foo = {
  message: 'Foooooooo'
};

var bar = {
  message: 'Barrrrrrr'
};

function say() {
  console.log(this.message);
}

say();
say.bind(foo)();
say.bind(foo).bind(bar)();
say.bind(foo).apply(bar);

// 执行之后如下
// undefined
// Foooooooo
// Foooooooo
// Foooooooo

我的问题是:为什么bind(foo)之后,不管是再bind其它对象,还是用apply改变this对象,都无法影响调用结果?

我个人理解为应该按最后bind或apply的this来调用才对啊。


3 回复

当然可以。让我们详细解释一下这段代码以及为什么会出现这样的结果。

代码分析

首先,我们来看一下这段代码:

var foo = {
  message: 'Foooooooo'
};

var bar = {
  message: 'Barrrrrrr'
};

function say() {
  console.log(this.message);
}

say(); // 输出: undefined

say.bind(foo)();
say.bind(foo).bind(bar)();
say.bind(foo).apply(bar);

1. say() 的输出

say() 直接调用时,this 默认指向全局对象(在浏览器中通常是 window),而在 Node.js 中则是 global 对象。由于全局对象没有 message 属性,因此输出 undefined

2. say.bind(foo)() 的输出

say.bind(foo) 创建了一个新的函数,该函数在调用时会将 this 绑定到 foo。因此,say.bind(foo)() 输出 Foooooooo

3. say.bind(foo).bind(bar)() 的输出

say.bind(foo).bind(bar) 实际上不会创建一个新的绑定。bind 方法返回的是一个新的函数,但第二次调用 bind 并不会覆盖第一次的绑定。因此,say.bind(foo).bind(bar)() 仍然会输出 Foooooooo,因为第一次绑定已经生效。

4. say.bind(foo).apply(bar) 的输出

apply 方法允许你显式地指定 this 的值。但是,即使你使用 apply 来改变 this 的值,say.bind(foo) 已经固定了 this 的绑定。因此,say.bind(foo).apply(bar) 仍然会输出 Foooooooo

总结

bind 方法一旦被调用,它会创建一个新的函数,该函数的 this 值已经被固定。后续的 bindapply 调用不会改变已经固定的 this 值。这就是为什么多次调用 bind 或使用 apply 都无法改变输出结果的原因。

示例代码

var foo = {
  message: 'Foooooooo'
};

var bar = {
  message: 'Barrrrrrr'
};

function say() {
  console.log(this.message);
}

console.log(say()); // 输出: undefined

let boundSay = say.bind(foo);
console.log(boundSay()); // 输出: Foooooooo

let boundSayAgain = boundSay.bind(bar); // 不会改变已固定的 this
console.log(boundSayAgain()); // 输出: Foooooooo

boundSay.apply(bar); // 使用 apply 改变 this,但已固定的 this 无法改变
// 输出: Foooooooo

希望这能帮助你更好地理解 bindthis 在 JavaScript 中的工作原理。


Function.prototype.bind = function (ctx) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
	    return this.apply(ctx, args.concat(arguments));
	};
};

在你的例子中,bind() 函数创建了一个新的函数,这个新函数会在调用时绑定到特定的对象。具体来说:

  1. say.bind(foo)(); 这一行将 say 函数绑定到了 foo 对象,所以输出了 "Foooooooo"
  2. say.bind(foo).bind(bar)(); 这里 say.bind(foo) 创建了一个新的函数,然后再次调用 .bind(bar) 又生成了一个新的函数。由于 bind 是不可逆的,第一次绑定已经固定了 this 的值为 foo,因此第二次绑定 bar 没有任何效果。最终还是输出了 "Foooooooo"
  3. say.bind(foo).apply(bar); 这里使用 apply 方法改变了 this 上下文,但由于 say.bind(foo) 已经绑定了 foo,所以这里的 apply 并不会改变 this 的绑定关系。你可以通过将 apply 放在 bind 调用链的末尾来改变 this 的上下文。

为了达到你预期的效果,可以这样做:

var foo = {
  message: 'Foooooooo'
};

var bar = {
  message: 'Barrrrrrr'
};

function say() {
  console.log(this.message);
}

var boundSay = say.bind(foo);
boundSay.apply(bar); // 输出 "Barrrrrrr"

这样,boundSay.apply(bar) 就会输出 "Barrrrrrr",因为 apply 直接改变了 this 的上下文。

回到顶部