JavaScript中的call()和apply()与bind()有什么区别?

996

我已经知道applycall是相似的函数,它们都可以设置函数的上下文(this)。

不同之处在于我们发送参数的方式(手动 vs 数组)。

问题:

但是什么时候应该使用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


15
如果有用户在发表回答或投票前查看主题发起人的声望积分,那并不是你的错 :) - Gabriel Llamas
81
call()apply()都是调用函数的方法,但bind()是创建一个新的函数。使用call()时,需要逐个传递参数;而使用apply()时,则需将参数作为数组传入。如需了解更多细节,请查看相关文档,它们可以完整地回答你的问题。 - Nope
4
有点奇怪,居然还没有关于这个的问题:关于这个,这可能是因为在JavaScript 1.8.5 - ECMA-262第5版中添加了bind(),而另外两个函数则已存在于JavaScript 1.3 - ECMA-262第3版中,例如关于它们的问题,Stack Overflow上有像what-is-the-difference-between-call-and-apply这样的问题。我只是猜测,因为我自己也在思考这个问题。 - Nope
这里的“call”和“Array.prototype.slice.call”中的“call”是同一个吗?后者也很难理解。 - David Spector
obj.call(arg) 和 func(arg) 一样吗?只是前者将 "this" 设置为 obj,以实现类实例方法? - David Spector
显示剩余3条评论
24个回答

12

Call、Apply和Bind的基本区别是:

如果你想让执行上下文稍后出现,则会使用Bind。

例如:

var car = { 
  registrationNumber: "007",
  brand: "Mercedes",

  displayDetails: function(ownerName){
    console.log(ownerName + ' this is your car ' + '' + this.registrationNumber + " " + this.brand);
  }
}
car.displayDetails('Nishant'); // **Nishant this is your car 007 Mercedes**

假设我想在其他变量中使用这个方法。

var car1 = car.displayDetails('Nishant');
car1(); // undefined

要在其他变量中使用车的引用,您应该使用

var car1 = car.displayDetails.bind(car, 'Nishant');
car1(); // Nishant this is your car 007 Mercedes

让我们谈一谈bind函数的更广泛应用

var func = function() {
 console.log(this)
}.bind(1);

func();
// Number: 1

为什么?因为现在func与数字1绑定在一起,如果我们不使用bind,在这种情况下它将指向全局对象。

var func = function() {
 console.log(this)
}.bind({});

func();
// Object

当您想要同时执行语句时,可以使用Call和Apply。

var Name = { 
    work: "SSE",
    age: "25"
}

function displayDetails(ownerName) {
    console.log(ownerName + ", this is your name: " + 'age' + this.age + " " + 'work' + this.work);
}
displayDetails.call(Name, 'Nishant')
// Nishant, this is your name: age25 workSSE

// In apply we pass an array of arguments
displayDetails.apply(Name, ['Nishant'])
// Nishant, this is your name: age25 workSSE

11

call/apply 立即执行函数:

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

bind 不会立即执行函数,而是返回一个封装的 apply 函数(以便稍后执行):

bind 不立即执行函数,而是返回包装好的 apply 函数(以便稍后执行):

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

9

调用apply和bind,以及它们之间的区别。

让我们使用日常术语来学习apply和call。

你有三辆车:your_scooter,your_car和your_jet,它们都使用相同的机制(方法)启动。我们创建了一个带有方法push_button_engineStart的对象automobile

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。假设您是一名工程师,拥有未配备推按钮引擎启动器的your_scooteryour_caryour_jet,并且您希望使用第三方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);

所以上述示例成功地将汽车对象的功能赋予了你的摩托车、你的汽车和你的飞机等。
让我们深入探讨一下。在这里,我们将拆分上面的代码行。automobile.push_button_engineStart帮助我们获取正在使用的方法。
进一步地,我们使用点号表示法来使用apply或call。
现在,apply和call接受两个参数。
上面的代码中,在最后一行中,我们设置了上下文(context)。
区别在于,apply接受以数组形式的参数,而call只能接受逗号分隔的参数列表。
JS Bind函数是什么?
绑定(bind)函数基本上是将某些东西的上下文绑定并存储到变量中,以便稍后执行。
让我们使我们之前的示例变得更好。之前,我们使用属于汽车对象的方法,并用它来装备你的汽车、你的飞机和你的摩托车。现在,让我们想象一下,我们想要单独为每辆车提供一个独立的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);

还不满意吗?

让我们把它讲得清晰明了。现在是实验的时候了。我们将回到调用和应用函数应用程序,并尝试将函数的值存储为引用。

以下实验失败,因为调用和应用是立即调用的,因此我们从未达到将引用存储在变量中的阶段,这就是绑定函数发挥作用的地方。

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


9

语法

  • call(thisArg, arg1, arg2, ...)
  • apply(thisArg, argsArray)
  • bind(thisArg[, arg1[, arg2[, ...]]])

这里

  • thisArg是对象
  • argsArray是数组对象
  • arg1,arg2,arg3等是额外的参数

function printBye(message1, message2){
    console.log(message1 + " " + this.name + " "+ message2);
}

var par01 = { name:"John" };
var msgArray = ["Bye", "Never come again..."];

printBye.call(par01, "Bye", "Never come again...");
//Bye John Never come again...

printBye.call(par01, msgArray);
//Bye,Never come again... John undefined

//so call() doesn't work with array and better with comma seperated parameters 

//printBye.apply(par01, "Bye", "Never come again...");//Error

printBye.apply(par01, msgArray);
//Bye John Never come again...

var func1 = printBye.bind(par01, "Bye", "Never come again...");
func1();//Bye John Never come again...

var func2 = printBye.bind(par01, msgArray);
func2();//Bye,Never come again... John undefined
//so bind() doesn't work with array and better with comma seperated parameters


6

JavaScript Call()

const person = {
    name: "Lokamn",
    dob: 12,
    print: function (value,value2) {
        console.log(this.dob+value+value2)
    }
}
const anotherPerson= {
     name: "Pappu",
     dob: 12,
}
 person.print.call(anotherPerson,1,2)

JavaScript apply()

    name: "Lokamn",
    dob: 12,
    print: function (value,value2) {
        console.log(this.dob+value+value2)
    }
}
const anotherPerson= {
     name: "Pappu",
     dob: 12,
}
 person.print.apply(anotherPerson,[1,2])

调用和应用函数的区别在于,调用会分别接受参数,而应用则接受数组,例如 [1,2,3]。

JavaScript bind()

    name: "Lokamn",
    dob: 12,
    anotherPerson: {
        name: "Pappu",
        dob: 12,
        print2: function () {
            console.log(this)
        }
    }
}

var bindFunction = person.anotherPerson.print2.bind(person)
 bindFunction()

5

Call: call 调用函数并允许你逐个传递参数

Apply: apply 调用函数并允许你将参数作为一个数组传递

Bind: bind 返回一个新的函数,允许你传入 this 数组和任意数量的参数。

var person1 = {firstName: 'Raju', lastName: 'king'};
var person2 = {firstName: 'chandu', lastName: 'shekar'};

function greet(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}
function greet2(greeting) {
        console.log( 'Hello ' + this.firstName + ' ' + this.lastName);
    }


greet.call(person1, 'Hello'); // Hello Raju king
greet.call(person2, 'Hello'); // Hello chandu shekar



greet.apply(person1, ['Hello']); // Hello Raju king
greet.apply(person2, ['Hello']); // Hello chandu shekar

var greetRaju = greet2.bind(person1);
var greetChandu = greet2.bind(person2);

greetRaju(); // Hello Raju king
greetChandu(); // Hello chandu shekar


5

call() :-- 在这里,我们逐个传递函数参数,而不是以数组格式。

var obj = {name: "Raushan"};

var greeting = function(a,b,c) {
    return "Welcome "+ this.name + " to "+ a + " " + b + " in " + c;
};

console.log(greeting.call(obj, "USA", "INDIA", "ASIA"));

apply() :-- 在这里,我们以数组格式传递函数参数。

var obj = {name: "Raushan"};

var cal = function(a,b,c) {
    return this.name +" you got " + a+b+c;
};

var arr =[1,2,3];  // array format for function arguments
console.log(cal.apply(obj, arr)); 

bind() :--

       var obj = {name: "Raushan"};

       var cal = function(a,b,c) {
            return this.name +" you got " + a+b+c;
       };

       var calc = cal.bind(obj);
       console.log(calc(2,3,4));

3
    function sayHello() {
            //alert(this.message);
            return this.message;
    }
    var obj = {
            message: "Hello"
    };

    function x(country) {
            var z = sayHello.bind(obj);
            setTimeout(y = function(w) {
//'this' reference not lost
                    return z() + ' ' + country + ' ' + w;
            }, 1000);
            return y;
    }
    var t = x('India')('World');
    document.getElementById("demo").innerHTML = t;

3
想象一下,如果bind不可用,你可以按照以下方式轻松构建它:
var someFunction=...
var objToBind=....

var bindHelper =  function (someFunction, objToBind) {
    return function() {
        someFunction.apply( objToBind, arguments );
    };  
}

bindHelper(arguments);

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接