何时在JS中使用.bind()

When to use .bind() in JS

本文关键字:bind JS 何时      更新时间:2023-09-26

有很多关于如何使用bind()以及它与call()apply()有何不同的博客和帖子,但很少有何时为什么应该使用bind() 的例子

我发现给出的许多例子都是非常罕见的,比如:

"use strict";
function Person(firstName, lastName){
  this.firstName = firstName
  this.lastName = lastName
}
Person.prototype.say = function(message){
  return '[' + this + ']: ' + this.firstName + ' ' + this.lastName + ' said: "' + message + '"'
}
Person.prototype.toString = function(){
  return '[Person]'
}
moe = new Person("Mo", "El")

func = moe.say.bind(moe)
console.log(func("asdasda"))

我不知道什么时候我想让一个函数等于其他变量,并使用该变量而不是原始函数,更不用说该变量等于Person对象实例的绑定了。

有什么好的例子吗?

简而言之,.bind()返回一个新函数,当被调用时,该函数将调用具有特定this值的原始函数,以及(可选)一些预存到参数列表中的新参数。

当您需要传递回调(例如某种函数引用),但您希望调用方使用特定的this值调用您的函数时,会使用.bind()。当您的函数实际上是一个方法,并且您希望this值集是一个特定对象时,这种情况最为常见,因此该方法将对该特定对象进行操作。如果在这些情况下不使用.bind(),那么this的值将由调用者(而不是您)确定,如果调用者没有具体设置,它最终将成为全局对象或(在严格模式下)undefined。如果您传递的方法依赖于this的特定值来完成其工作,那么它将无法使用错误的this值正常工作。

因此,如果您想在调用回调时控制this的值,可以使用.bind()。在内部,.bind()只创建一个小的存根函数,它只记住您传递的this值,并用.apply()调用您的函数来设置this值。.bind()并不神奇,因为它也可以手动完成。

.bind()还可以向函数添加额外的参数,因此,如果您想添加超出回调的正常调用方使用的参数,也可以使用.bind()指定这些参数。它创建了一个存根函数,该函数将添加这些额外的参数并设置this值。


假设您有一个Person对象,并且想要将一个按钮挂接到特定Person对象的.say()方法。

<button id="talk">Talk</button>

而且,如果你尝试了这个javascript:

"use strict";
var bob = new Person("Bob", "Smith");
document.getElementById("talk").addEventListener("click", bob.say);

您会发现调用了say()方法,但它缺少两件事。它将缺少正确的this引用(它将被设置为button对象,因为addEventListener就是这样调用它的回调的),并且它将缺少say(message)所期望的参数。

因此,您可以使用自己的存根函数来解决这个问题,该函数使用所有正确的参数调用bob.say()

"use strict";
var bob = new Person("Bob", "Smith");
document.getElementById("talk").addEventListener("click", function(e) {
    bob.say("Hello");
});

或者,您可以使用.bind():

"use strict";
var bob = new Person("Bob", "Smith");
document.getElementById("talk").addEventListener("click", bob.say.bind(bob, "Hello"));

.bind()没有魔法。它可以完全用javascript进行模拟。事实上,这里有一个来自MDN:的polyfill

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;
  };
}

由于所有的错误检查,这看起来可能比实际情况更复杂,但实际上它只是返回一个新函数,该函数将两组参数组合在一起,然后用特定的this值调用原始函数。

这可能是从实际意义上解释它的最简单方法。由于大多数答案都给出了理论定义和解释,我将展示一个简单的用例。当您希望被调用的函数具有与默认值不同的this值时,可以使用bind。

var NS = {
  user     : "self",
  getUser  : function() { return this.user; }
};
var CLOSURE = NS.getUser;
// error user is undefined, "this" in that context refers to the global object, "window"
console.log(CLOSURE());
// Bind the function call to NS object
console.log(CLOSURE.bind(NS)());

http://jsfiddle.net/ev3z3td3/2/

如果希望函数始终以特定的this值运行,请使用bind()

当将函数作为回调或事件处理程序传递时,它对于更多的函数编程非常有用。

var User = function(name) { this.name = name; };
User.prototype.poke = function() { alert "Hey, don't poke " + this.name; };
var bob = User('Bob');
// assume jQuery for brevity, and because it screws with `this` in callbacks
$('#some-element').click(bob.poke.bind(bob));

这会提醒"嘿,不要戳Bob",因为你给它传递了一个绑定函数。因此,如果该元素明确地与Bob有关,那么将事件处理程序绑定到Bob是有意义的。


当然,在没有bind的情况下,还有其他方法可以做到这一点。

$('#some-element').click(function() {
  bob.poke();
});

差异可能是风格的问题。bind过去并不是在所有浏览器中都有很多支持,所以很多JS程序员想出了其他方法来实现这一点,而且很多其他方法至今仍在使用。


当您想要将相同的函数传递到许多不同的地方,并且想要显式设置的this时,clear的一个优点是。

var bobPoke = bob.poke.bind(bob);
onFoo(bobPoke);
onBar(bobPoke);
onBaz(bobPoke);