Javascript call() & apply() vs bind()?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15455009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript call() & apply() vs bind()?
提问by Royi Namir
I already know that apply
and call
are similar functions which setthis
(context of a function).
我已经知道了,apply
并且call
是类似的函数,它们设置this
(函数的上下文)。
The difference is with the way we send the arguments (manual vs array)
不同之处在于我们发送参数的方式(手动 vs 数组)
Question:
问题:
But when should I use the bind()
method ?
但是我应该什么时候使用该 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));
采纳答案by Felix Kling
I created this comparison between function objects, function calls, call/apply
and bind
a while ago:
我创建函数对象,函数调用之间的比较call/apply
和bind
前一段时间:
.bind
allows you to set the this
value nowwhile allowing you to execute the function in the future, because it returns a new function object.
.bind
允许您现在设置this
值,同时允许您将来执行该函数,因为它返回一个新的函数对象。
回答by Chad
Use .bind()
when you want that function to later be called with a certain context, useful in events. Use .call()
or .apply()
when you want to invoke the function immediately, and modify the context.
.bind()
当您希望稍后使用特定上下文调用该函数时使用,这在事件中很有用。当您想立即调用该函数并修改上下文时使用.call()
或.apply()
。
Call/apply call the function immediately, whereas bind
returns a function that, when later executed, will have the correct context set for calling the original function. This way you can maintain context in async callbacks and events.
Call/apply 立即调用该函数,而bind
返回一个函数,该函数在稍后执行时将具有用于调用原始函数的正确上下文集。通过这种方式,您可以在异步回调和事件中维护上下文。
I do this a lot:
我经常这样做:
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.
};
I use it extensively in Node.js for async callbacks that I want to pass a member method for, but still want the context to be the instance that started the async action.
我在 Node.js 中广泛地将它用于异步回调,我想为其传递成员方法,但仍然希望上下文是启动异步操作的实例。
A simple, naive implementation of bind would be like:
一个简单的 bind 实现如下:
Function.prototype.bind = function(ctx) {
var fn = this;
return function() {
fn.apply(ctx, arguments);
};
};
There is more to it (like passing other args), but you can read more about it and see the real implementation on the MDN.
它还有更多内容(如传递其他参数),但您可以阅读更多关于它的内容,并在 MDN 上查看真正的实现。
Hope this helps.
希望这可以帮助。
回答by CuriousSuperhero
They all attach thisinto function (or object) and the difference is in the function invocation (see below).
它们都将this附加到函数(或对象)中,区别在于函数调用(见下文)。
callattaches thisinto function and executes the function immediately:
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"
bindattaches thisinto function and it needs to be invoked separately like this:
bind将this附加到函数中,它需要像这样单独调用:
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"
or like this:
或者像这样:
...
var helloFunc = person.hello.bind({ name: "Jim Smith" }, "world");
helloFunc(); // output: Jim Smith says hello world"
applyis similar to callexcept that it takes an array-like object instead of listing the arguments out one at a time:
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"
回答by Amit Shah
Answer in SIMPLEST form
以最简单的形式回答
- Callinvokes the function and allows you to pass in arguments one by one.
- Applyinvokes the function and allows you to pass in arguments as an array.
- Bindreturns a new function, allowing you to pass in a this array and any number of arguments.
- Call调用该函数并允许您一一传递参数。
- Apply调用该函数并允许您将参数作为数组传递。
- Bind返回一个新函数,允许你传入一个 this 数组和任意数量的参数。
Apply vs. Call vs. Bind Examples
应用与调用与绑定示例
Call
称呼
var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};
function say(greeting) {
console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}
say.call(person1, 'Hello'); // Hello Jon Kuperman
say.call(person2, 'Hello'); // Hello Kelly King
Apply
申请
var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};
function say(greeting) {
console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}
say.apply(person1, ['Hello']); // Hello Jon Kuperman
say.apply(person2, ['Hello']); // Hello Kelly King
Bind
绑定
var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};
function say() {
console.log('Hello ' + this.firstName + ' ' + this.lastName);
}
var sayHelloJon = say.bind(person1);
var sayHelloKelly = say.bind(person2);
sayHelloJon(); // Hello Jon Kuperman
sayHelloKelly(); // Hello Kelly King
When To Use Each
何时使用
Call and apply are pretty interchangeable. Just decide whether it's easier to send in an array or a comma separated list of arguments.
Call 和 apply 可以互换。只需决定是否更容易发送数组或逗号分隔的参数列表。
I always remember which one is which by remembering that Call is for comma (separated list) and Apply is for Array.
通过记住 Call 用于逗号(分隔列表)和 Apply 用于数组,我总是记得哪个是哪个。
Bind is a bit different. It returns a new function. Call and Apply execute the current function immediately.
绑定有点不同。它返回一个新函数。Call 和 Apply 立即执行当前函数。
Bind is great for a lot of things. We can use it to curry functions like in the above example. We can take a simple hello function and turn it into a helloJon or helloKelly. We can also use it for events like onClick where we don't know when they'll be fired but we know what context we want them to have.
Bind 对很多事情都很有用。我们可以用它来柯里化上面例子中的函数。我们可以将一个简单的 hello 函数转换为 helloJon 或 helloKelly。我们还可以将它用于 onClick 之类的事件,我们不知道它们何时会被触发,但我们知道我们希望它们具有什么上下文。
Reference: codeplanet.io
回答by jantimon
It allows to set the value for this
independent of how the function is called. This is very useful when working with callbacks:
它允许设置this
独立于函数调用方式的值。这在处理回调时非常有用:
function sayHello(){
alert(this.message);
}
var obj = {
message : "hello"
};
setTimeout(sayHello.bind(obj), 1000);
To achieve the same result with call
would look like this:
要获得相同的结果,call
将如下所示:
function sayHello(){
alert(this.message);
}
var obj = {
message : "hello"
};
setTimeout(function(){sayHello.call(obj)}, 1000);
回答by tk120404
Assume we have multiplication
function
假设我们有multiplication
函数
function multiplication(a,b){
console.log(a*b);
}
Lets create some standard functions using bind
让我们创建一些标准函数使用 bind
var multiby2 = multiplication.bind(this,2);
var multiby2 = multiplication.bind(this,2);
Now multiby2(b) is equal to multiplication(2,b);
现在 multiby2(b) 等于 multiplication(2,b);
multiby2(3); //6
multiby2(4); //8
What if I pass both the parameters in bind
如果我在绑定中传递两个参数怎么办
var getSixAlways = multiplication.bind(this,3,2);
Now getSixAlways() is equal to multiplication(3,2);
现在 getSixAlways() 等于 multiplication(3,2);
getSixAlways();//6
even passing parameter returns 6;
getSixAlways(12); //6
即使传递参数返回6;
getSixAlways(12); //6
var magicMultiplication = multiplication.bind(this);
This create a new multiplication function and assigns it to magicMultiplication.
这将创建一个新的乘法函数并将其分配给 magicMultiplication。
Oh no, we are hiding the multiplication functionality into magicMultiplication.
哦不,我们将乘法功能隐藏在 magicMultiplication 中。
calling
magicMultiplication
returns a blank function b()
调用
magicMultiplication
返回空白function b()
on execution it works fine
magicMultiplication(6,5); //30
在执行时它工作正常
magicMultiplication(6,5); //30
How about call and apply?
打电话申请怎么样?
magicMultiplication.call(this,3,2); //6
magicMultiplication.call(this,3,2); //6
magicMultiplication.apply(this,[5,2]); //10
magicMultiplication.apply(this,[5,2]); //10
In simple words, bind
creates the function, call
and apply
executes the function whereas apply
expects the parameters in array
简单来说,bind
创建函数call
并apply
执行函数,而apply
期望数组中的参数
回答by John Slegers
Both Function.prototype.call()
and Function.prototype.apply()
call a function with a given this
value, and return the return value of that function.
双方Function.prototype.call()
并Function.prototype.apply()
调用具有给定函数this
值,并返回该函数的返回值。
Function.prototype.bind()
, on the other hand, creates a new function with a given this
value, and returns that function without executing it.
Function.prototype.bind()
,另一方面,创建一个具有给定this
值的新函数,并返回该函数而不执行它。
So, let's take a function that looks like this :
因此,让我们采用如下所示的函数:
var logProp = function(prop) {
console.log(this[prop]);
};
Now, let's take an object that looks like this :
现在,让我们看一个看起来像这样的对象:
var Obj = {
x : 5,
y : 10
};
We can bind our function to our object like this :
我们可以像这样将我们的函数绑定到我们的对象:
Obj.log = logProp.bind(Obj);
Now, we can run Obj.log
anywhere in our code :
现在,我们可以Obj.log
在代码中的任何地方运行:
Obj.log('x'); // Output : 5
Obj.log('y'); // Output : 10
Where it really gets interesting, is when you not only bind a value for this
, but also for for its argument prop
:
真正有趣的地方在于,您不仅为 绑定了值this
,还为其参数绑定了值prop
:
Obj.logX = logProp.bind(Obj, 'x');
Obj.logY = logProp.bind(Obj, 'y');
We can now do this :
我们现在可以这样做:
Obj.logX(); // Output : 5
Obj.logY(); // Output : 10
回答by Siddhartha
bind: It binds the function with provided value and context but it does not executes the function. To execute function you need to call the function.
bind:它将函数与提供的值和上下文绑定,但不执行函数。要执行函数,您需要调用该函数。
call: It executes the function with provided context and parameter.
call:它使用提供的上下文和参数执行函数。
apply: It executes the function with provided context and parameter as array.
apply:它使用提供的上下文和参数作为数组执行函数 。
回答by zangw
Here is one good articleto illustrate the difference among bind()
, apply()
and call()
, summarize it as below.
这是一篇很好的文章来说明bind()
,apply()
和之间的区别call()
,总结如下。
bind()
allows us to easily set which specific object will be bound to thiswhen a function or method is invoked.// This data variable is a global variable? var data = [ {name:"Samantha", age:12}, {name:"Alexis", age:14} ] var user = { // local data variable? data :[ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], showData:function (event) { var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1? console.log (this.data[randomNum].name + " " + this.data[randomNum].age); } } // Assign the showData method of the user object to a variable? var showDataVar = user.showData; showDataVar (); // Samantha 12 (from the global data array, not from the local data array)? /* This happens because showDataVar () is executed as a global function and use of this inside showDataVar () is bound to the global scope, which is the window object in browsers. */ // Bind the showData method to the user object? var showDataVar = user.showData.bind (user); // Now the we get the value from the user object because the this keyword is bound to the user object? showDataVar (); // P. Mickelson 43?
bind()
allow us to borrow methods// Here we have a cars object that does not have a method to print its data to the console? var cars = { data:[ {name:"Honda Accord", age:14}, {name:"Tesla Model S", age:2} ] } // We can borrow the showData () method from the user object we defined in the last example.? // Here we bind the user.showData method to the cars object we just created.? cars.showData = user.showData.bind (cars); cars.showData (); // Honda Accord 14?
One problem with this example is that we are adding a new method
showData
on thecars
object and we might not want to do that just to borrow a method because the cars object might already have a property or method nameshowData
. We don't want to overwrite it accidentally. As we will see in our discussion ofApply
andCall
below, it is best to borrow a method using either theApply
orCall
method.bind()
allow us to curry a functionFunction Currying, also known as partial function application, is the use of a function (that accept one or more arguments) that returns a new function with some of the arguments already set.
function greet (gender, age, name) { // if a male, use Mr., else use Ms.? var salutation = gender === "male" ? "Mr. " : "Ms. "; if (age > 25) { return "Hello, " + salutation + name + "."; }else { return "Hey, " + name + "."; } }
We can use
bind()
to curry thisgreet
function// So we are passing null because we are not using the "this" keyword in our greet function. var greetAnAdultMale = greet.bind (null, "male", 45); greetAnAdultMale ("John Hartlove"); // "Hello, Mr. John Hartlove." var greetAYoungster = greet.bind (null, "", 16); greetAYoungster ("Alex"); // "Hey, Alex."? greetAYoungster ("Emma Waterloo"); // "Hey, Emma Waterloo."
apply()
orcall()
to set thisvalueThe
apply
,call
, andbind
methods are all used to set the this value when invoking a method, and they do it in slightly different ways to allow use direct control and versatility in our JavaScript code.The
apply
andcall
methods are almost identical when setting the this value except that you pass the function parameters toapply ()
as an array, while you have to list the parameters individuallyto pass them to thecall ()
method.Here is one example to use
call
orapply
to set thisin the callback function.// Define an object with some properties and a method? // We will later pass the method as a callback function to another function? var clientData = { id: 094545, fullName: "Not Set", // setUserName is a method on the clientData object? setUserName: function (firstName, lastName) { // this refers to the fullName property in this object? this.fullName = firstName + " " + lastName; } }; function getUserInput (firstName, lastName, callback, callbackObj) { // The use of the Apply method below will set the "this" value to callbackObj? callback.apply (callbackObj, [firstName, lastName]); } // The clientData object will be used by the Apply method to set the "this" value? getUserInput ("Barack", "Obama", clientData.setUserName, clientData); // the fullName property on the clientData was correctly set? console.log (clientData.fullName); // Barack Obama
Borrow functions with
apply
orcall
Borrow Array methods
Let's create an
array-like
object and borrow some array methods to operate on the our array-like object.// An array-like object: note the non-negative integers used as keys? var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 }; // Make a quick copy and save the results in a real array: // First parameter sets the "this" value? var newArray = Array.prototype.slice.call (anArrayLikeObj, 0); console.log (newArray); // ["Martin", 78, 67, Array[3]]? // Search for "Martin" in the array-like object? console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true?
Another common case is that convert
arguments
to array as following// We do not define the function with any parameters, yet we can get all the arguments passed to it? function doSomething () { var args = Array.prototype.slice.call (arguments); console.log (args); } doSomething ("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"]
Borrow other methods
var gameController = { scores :[20, 34, 55, 46, 77], avgScore:null, players :[ {name:"Tommy", playerID:987, age:23}, {name:"Pau", playerID:87, age:33} ] } var appController = { scores :[900, 845, 809, 950], avgScore:null, avg :function () { var sumOfScores = this.scores.reduce (function (prev, cur, index, array) { return prev + cur; }); this.avgScore = sumOfScores / this.scores.length; } } // Note that we are using the apply () method, so the 2nd argument has to be an array? appController.avg.apply (gameController); console.log (gameController.avgScore); // 46.4? // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated? console.log (appController.avgScore); // null?
Use
apply()
to execute variable-arityfunction
bind()
允许我们轻松设置调用函数或方法时将绑定到this 的特定对象。// This data variable is a global variable? var data = [ {name:"Samantha", age:12}, {name:"Alexis", age:14} ] var user = { // local data variable? data :[ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], showData:function (event) { var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1? console.log (this.data[randomNum].name + " " + this.data[randomNum].age); } } // Assign the showData method of the user object to a variable? var showDataVar = user.showData; showDataVar (); // Samantha 12 (from the global data array, not from the local data array)? /* This happens because showDataVar () is executed as a global function and use of this inside showDataVar () is bound to the global scope, which is the window object in browsers. */ // Bind the showData method to the user object? var showDataVar = user.showData.bind (user); // Now the we get the value from the user object because the this keyword is bound to the user object? showDataVar (); // P. Mickelson 43?
bind()
允许我们借用方法// Here we have a cars object that does not have a method to print its data to the console? var cars = { data:[ {name:"Honda Accord", age:14}, {name:"Tesla Model S", age:2} ] } // We can borrow the showData () method from the user object we defined in the last example.? // Here we bind the user.showData method to the cars object we just created.? cars.showData = user.showData.bind (cars); cars.showData (); // Honda Accord 14?
这个例子的一个问题是我们
showData
在cars
对象上添加了一个新方法,我们可能不想这样做只是为了借用一个方法,因为汽车对象可能已经有一个属性或方法名称showData
。我们不想意外覆盖它。正如我们将在我们的讨论中看到Apply
和Call
下面,最好是借使用A方法Apply
或Call
方法。bind()
允许我们柯里化一个函数函数柯里化,也称为部分函数应用程序,是使用一个函数(接受一个或多个参数)返回一个新函数,其中一些参数已经设置。
function greet (gender, age, name) { // if a male, use Mr., else use Ms.? var salutation = gender === "male" ? "Mr. " : "Ms. "; if (age > 25) { return "Hello, " + salutation + name + "."; }else { return "Hey, " + name + "."; } }
我们可以用
bind()
咖喱这个greet
函数// So we are passing null because we are not using the "this" keyword in our greet function. var greetAnAdultMale = greet.bind (null, "male", 45); greetAnAdultMale ("John Hartlove"); // "Hello, Mr. John Hartlove." var greetAYoungster = greet.bind (null, "", 16); greetAYoungster ("Alex"); // "Hey, Alex."? greetAYoungster ("Emma Waterloo"); // "Hey, Emma Waterloo."
apply()
或call()
设置此值的
apply
,call
和bind
方法都是使用调用方法时设置这个值,他们这样做稍微不同的方式,让我们的JavaScript代码中使用直接控制和多功能性。设置 this 值时,
apply
和call
方法几乎相同,只是将函数参数apply ()
作为数组传递给,而您必须单独列出参数才能将它们传递给call ()
方法。这是在回调函数中使用
call
或apply
设置它的一个示例。// Define an object with some properties and a method? // We will later pass the method as a callback function to another function? var clientData = { id: 094545, fullName: "Not Set", // setUserName is a method on the clientData object? setUserName: function (firstName, lastName) { // this refers to the fullName property in this object? this.fullName = firstName + " " + lastName; } }; function getUserInput (firstName, lastName, callback, callbackObj) { // The use of the Apply method below will set the "this" value to callbackObj? callback.apply (callbackObj, [firstName, lastName]); } // The clientData object will be used by the Apply method to set the "this" value? getUserInput ("Barack", "Obama", clientData.setUserName, clientData); // the fullName property on the clientData was correctly set? console.log (clientData.fullName); // Barack Obama
借用函数
apply
或call
借用数组方法
让我们创建一个
array-like
对象并借用一些数组方法来操作我们的类数组对象。// An array-like object: note the non-negative integers used as keys? var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 }; // Make a quick copy and save the results in a real array: // First parameter sets the "this" value? var newArray = Array.prototype.slice.call (anArrayLikeObj, 0); console.log (newArray); // ["Martin", 78, 67, Array[3]]? // Search for "Martin" in the array-like object? console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true?
另一种常见情况是转换
arguments
为数组如下// We do not define the function with any parameters, yet we can get all the arguments passed to it? function doSomething () { var args = Array.prototype.slice.call (arguments); console.log (args); } doSomething ("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"]
借用其他方法
var gameController = { scores :[20, 34, 55, 46, 77], avgScore:null, players :[ {name:"Tommy", playerID:987, age:23}, {name:"Pau", playerID:87, age:33} ] } var appController = { scores :[900, 845, 809, 950], avgScore:null, avg :function () { var sumOfScores = this.scores.reduce (function (prev, cur, index, array) { return prev + cur; }); this.avgScore = sumOfScores / this.scores.length; } } // Note that we are using the apply () method, so the 2nd argument has to be an array? appController.avg.apply (gameController); console.log (gameController.avgScore); // 46.4? // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated? console.log (appController.avgScore); // null?
使用
apply()
执行可变元数函数
The Math.max
is one example of variable-arity function,
这Math.max
是可变元函数的一个例子,
// We can pass any number of arguments to the Math.max () method?
console.log (Math.max (23, 11, 34, 56)); // 56
But what if we have an array of numbers to pass to Math.max
? We cannot do this:
但是如果我们有一个数字数组要传递给它Math.max
呢?我们不能这样做:
var allNumbers = [23, 11, 34, 56];
// We cannot pass an array of numbers to the the Math.max method like this?
console.log (Math.max (allNumbers)); // NaN
This is where the apply ()
method helps us execute variadic functions. Instead of the above, we have to pass the array of numbers using apply (
) thus:
这是apply ()
方法帮助我们执行可变参数函数的地方。代替上面的,我们必须使用apply (
)传递数字数组,因此:
var allNumbers = [23, 11, 34, 56];
// Using the apply () method, we can pass the array of numbers:
console.log (Math.max.apply (null, allNumbers)); // 56
回答by Eldiyar Talantbek
call/applyexecutes function immediately:
call/apply立即执行函数:
func.call(context, arguments);
func.apply(context, [argument1,argument2,..]);
binddoesn't execute function immediately, but returns wrapped applyfunction (for later execution):
bind不会立即执行函数,而是返回包装好的apply函数(供以后执行):
function bind(func, context) {
return function() {
return func.apply(context, arguments);
};
}