我已经知道apply和call是类似的函数,它们设置this(函数的上下文)。

区别在于我们发送参数的方式(manual vs array)

问题:

但是什么时候应该使用bind()方法呢?

var obj = {
  x: 81,
  getX: function() {
    return this.x;
  }
};

alert(obj.getX.bind(obj)());
alert(obj.getX.call(obj));
alert(obj.getX.apply(obj));

jsbin


当前回答

当您希望稍后在特定上下文中调用该函数(在事件中很有用)时,请使用.bind()。当您希望立即调用函数并修改上下文时,请使用.call()或.apply()。

Call/apply立即调用该函数,而bind返回的函数在稍后执行时将具有用于调用原始函数的正确上下文设置。这样你就可以在异步回调和事件中维护上下文。

我经常这样做:

function MyObject(element) {
    this.elm = element;

    element.addEventListener('click', this.onClick.bind(this), false);
};

MyObject.prototype.onClick = function(e) {
     var t=this;  //do something with [t]...
    //without bind the context of this function wouldn't be a MyObject
    //instance as you would normally expect.
};

我在Node.js中广泛使用它,用于我想要传递成员方法的异步回调,但仍然希望上下文是启动异步操作的实例。

bind的简单实现如下所示:

Function.prototype.bind = function(ctx) {
    var fn = this;
    return function() {
        fn.apply(ctx, arguments);
    };
};

还有更多关于它的内容(比如传递其他参数),但您可以阅读更多关于它的内容,并查看MDN上的实际实现。

其他回答

当我们想要分配一个具有特定上下文的函数时,应该使用Bind函数。

var demo = {
           getValue : function(){ 
             console.log('demo object get value       function') 
            }
           setValue : function(){  
              setTimeout(this.getValue.bind(this),1000)           
           }
 }

在上面的例子中,如果我们调用demo.setValue()函数并传递这个。getValue函数,那么它不会调用demo。setValue函数,因为setTimeout中的this指向窗口对象,所以我们需要将演示对象context传递给this。getValue函数使用bind。这意味着我们只是将demo对象的上下文传递给function,而不是实际调用function。

希望你能理解。

更多信息请参考 Javascript绑定函数详细了解

调用/apply立即执行函数:

func.call(context, arguments);
func.apply(context, [argument1,argument2,..]);

Bind不会立即执行函数,而是返回包装好的apply函数(供以后执行):

function bind(func, context) {
    return function() {
        return func.apply(context, arguments);
    };
}

它们都将其附加到函数(或对象)中,区别在于函数调用(见下文)。

Call将此附加到函数中并立即执行函数:

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
person.hello.call({ name: "Jim Smith" }, "world"); // output: "Jim Smith says hello world"

Bind将它附加到函数中,需要像这样单独调用:

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
var helloFunc = person.hello.bind({ name: "Jim Smith" });
helloFunc("world");  // output: Jim Smith says hello world"

或者像这样:

...    
var helloFunc = person.hello.bind({ name: "Jim Smith" }, "world");
helloFunc();  // output: Jim Smith says hello world"

Apply类似于call,只是它接受一个类似数组的对象,而不是一次列出一个参数:

function personContainer() {
  var person = {  
     name: "James Smith",
     hello: function() {
       console.log(this.name + " says hello " + arguments[1]);
     }
  }
  person.hello.apply(person, arguments);
}
personContainer("world", "mars"); // output: "James Smith says hello mars", note: arguments[0] = "world" , arguments[1] = "mars"                                     

调用apply和bind。以及它们的不同之处。

让我们学习如何使用日常术语。

你有三辆汽车,你的摩托车,你的汽车和你的喷气式飞机,它们以相同的机制(方法)开始。 我们使用push_button_engineStart方法创建了一个对象汽车。

var your_scooter, your_car, your_jet;
var automobile = {
        push_button_engineStart: function (runtime){
        console.log(this.name + "'s" + ' engine_started, buckle up for the ride for ' + runtime + " minutes");
    }
}

让我们理解什么时候使用call和apply。让我们假设你是一名工程师,你有你的摩托车,你的汽车和你的喷气式飞机,这些都没有push_button_engine_start,你希望使用第三方push_button_engineStart。

如果运行以下代码行,它们将给出一个错误。为什么?

//your_scooter.push_button_engineStart();
//your_car.push_button_engineStart();
//your_jet.push_button_engineStart();


automobile.push_button_engineStart.apply(your_scooter,[20]);
automobile.push_button_engineStart.call(your_jet,10);
automobile.push_button_engineStart.call(your_car,40);

上面的例子成功地给了your_scooter, your_car, your_jet一个automobile对象的特征。

让我们再深入一点 在这里,我们将拆分上面的代码行。 汽车。push_button_engineStart帮助我们获取正在使用的方法。

此外,我们使用点表示法使用apply或call。 automobile.push_button_engineStart.apply ()

现在应用和调用accept两个参数。

上下文 参数

这里我们在最后一行代码中设置了context。

automobile.push_button_engineStart.apply (your_scooter [20])

call和apply的区别在于apply接受数组形式的形参,而call只能接受以逗号分隔的参数列表。

什么是JS绑定函数?

绑定函数基本上就是绑定某个东西的上下文,然后将其存储到一个变量中,以便在稍后阶段执行。

让我们把前面的例子做得更好。之前我们使用了一个属于automobile对象的方法,并使用它来装备你的car、你的jet和你的scooter。现在让我们想象一下,我们想要分别给出一个单独的push_button_engineStart,在我们希望的执行的任何后续阶段分别启动我们的汽车。

var scooty_engineStart = automobile.push_button_engineStart.bind(your_scooter);
var car_engineStart = automobile.push_button_engineStart.bind(your_car);
var jet_engineStart = automobile.push_button_engineStart.bind(your_jet);


setTimeout(scooty_engineStart,5000,30);
setTimeout(car_engineStart,10000,40);
setTimeout(jet_engineStart,15000,5);

还不满意?

让我们像泪滴一样说清楚。是时候做实验了。我们将返回到调用和应用函数应用程序,并尝试将函数的值存储为引用。

下面的实验失败了,因为call和apply是立即调用的,因此,我们从来没有达到在变量中存储引用的阶段,这是bind函数的亮点

var test_function = automobile.push_button_engineStart.apply(your_scooter);

function. prototype.call()和function. prototype.apply()都使用给定的这个值调用函数,并返回该函数的返回值。

另一方面,function .prototype.bind()使用给定的这个值创建一个新函数,并返回该函数而不执行它。

让我们取一个这样的函数:

var logProp = function(prop) {
    console.log(this[prop]);
};

现在,让我们选择一个这样的对象:

var Obj = {
    x : 5,
    y : 10
};

我们可以像这样将函数绑定到对象上:

Obj.log = logProp.bind(Obj);

现在,我们可以在代码中的任何地方运行Obj.log:

Obj.log('x'); // Output : 5
Obj.log('y'); // Output : 10

真正有趣的是,你不仅为this绑定了一个值,还为它的参数prop绑定了一个值:

Obj.logX = logProp.bind(Obj, 'x');
Obj.logY = logProp.bind(Obj, 'y');

我们现在可以这样做:

Obj.logX(); // Output : 5
Obj.logY(); // Output : 10