Javascript调用()&apply()vs bind()?
我已经知道apply
和call
是设置this
(函数的上下文)类似的function。
不同的是我们发送参数的方式(手动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
当你希望这个函数稍后被一个特定的上下文调用时,使用.bind()
,在事件中很有用。 如果要立即调用该函数,请使用.apply()
.call()
或.apply()
,并修改上下文。
调用/应用程序立即调用该函数,而bind
返回一个函数,稍后执行时,将具有正确的上下文设置调用原始函数。 这样你可以维护asynchronouscallback和事件的上下文。
我做了很多:
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中广泛地使用它来进行asynchronouscallback,我想传递一个成员方法,但仍然希望上下文成为启动asynchronous操作的实例。
一个简单的,天真的绑定实现就像:
Function.prototype.bind = function(ctx) { var fn = this; return function() { fn.apply(ctx, arguments); }; };
还有更多的东西(比如传递其他的参数),但是你可以阅读更多关于它的信息,并在MDN上看到真正的实现。
希望这可以帮助。
它们全部附加到函数(或对象)中,不同之处在于函数调用(见下文)。
调用 将该函数附加到函数中并立即执行该函数:
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"
绑定将其附加到函数中,并需要像这样分别调用它:
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"
应用类似于调用,只不过它需要一个类似数组的对象,而不是一次列出一个参数:
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"
它允许独立于函数的调用方式设置值。 使用callback函数时,这非常有用:
function sayHello(){ alert(this.message); } var obj = { message : "hello" }; setTimeout(sayHello.bind(obj), 1000);
为了达到与call
相同的结果将如下所示:
function sayHello(){ alert(this.message); } var obj = { message : "hello" }; setTimeout(function(){sayHello.call(obj)}, 1000);
假设我们有multiplication
函数
function multiplication(a,b){ console.log(a*b); }
让我们使用bind
创build一些标准函数
var multiby2 = multiplication.bind(this,2);
现在multiby2(b)等于乘法(2,b);
multiby2(3); //6 multiby2(4); //8
如果我通过绑定两个参数呢?
var getSixAlways = multiplication.bind(this,3,2);
现在getSixAlways()等于乘法(3,2);
getSixAlways();//6
即使传递参数返回6; getSixAlways(12); //6
var magicMultiplication = multiplication.bind(this);
这将创build一个新的乘法函数并将其分配给magicMultiplication。
哦,不,我们将乘法function隐藏到magicMultiplication中。
调用magicMultiplication
返回一个空白function b()
在执行时,它工作正常magicMultiplication(6,5); //30
magicMultiplication(6,5); //30
如何打电话和申请?
magicMultiplication.call(this,3,2); //6
magicMultiplication.apply(this,[5,2]); //10
简单地说, bind
创build函数, call
apply
执行函数而apply
期望数组中的参数
Function.prototype.call()
和Function.prototype.apply()
用给定的this
值调用一个函数,并返回该函数的返回值。
另一方面, Function.prototype.bind()
用给定的this
值创build一个新的函数,并返回该函数而不执行它。
所以,让我们看看这样的function:
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
这里有一篇很好的文章来说明bind()
, apply()
和call()
之间的区别, call()
按照下面的内容进行总结。
-
bind()
允许我们在调用函数或方法时很容易地设置哪个特定的对象将被绑定到这个对象上。// 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
这个例子的一个问题是,我们正在
cars
对象上添加一个新的方法showData
,我们可能不想这样做只是借用一个方法,因为汽车对象可能已经有一个属性或方法名称showData
。 我们不想意外覆盖它。 正如我们在下面的“Apply
和Call
讨论中所看到的,最好使用“Apply
或“Call
方法来借用方法。 -
bind()
允许我们来一个函数函数Currying (也称为部分函数应用程序 )是使用函数(接受一个或多个参数),返回一个新的函数,其中已经设置了一些参数。
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代码中使用直接控制和多function性。除了将函数parameter passing给
apply ()
作为数组外,apply
和call
方法在设置此值时几乎是相同的,而您必须单独列出参数以将它们传递给call ()
方法。这里是一个使用
call
或apply
来设置callback函数的例子。// 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
借用函数-
借用数组方法
让我们创build一个
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()
来执行variables函数
Math.max
是variables函数的一个例子,
// We can pass any number of arguments to the Math.max () method console.log (Math.max (23, 11, 34, 56)); // 56
但是如果我们有一组数字传递给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
这是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
以SIMPLESTforms回答
- 调用调用该函数并允许您逐个传递参数。
- 应用调用该函数并允许您将参数作为数组传递。
- 绑定返回一个新的函数,允许你传递一个这个数组和任意数量的参数。
应用与调用与绑定示例
呼叫
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
应用
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
捆绑
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
何时使用每个
打电话和申请是可以互换的。 只要决定发送数组还是以逗号分隔的参数列表更容易。
我总是记得哪一个是通过记住Call是逗号(分隔列表),而Apply是Array。
绑定有点不同。 它返回一个新的function。 调用并应用立即执行当前函数。
绑定对很多事情来说都很好。 我们可以像上面的例子一样使用它来实现咖喱function。 我们可以采取一个简单的hello函数,把它变成helloJon或helloKelly。 我们还可以将它用于像onClick这样的事件,我们不知道什么时候会被解雇,但我们知道我们希望他们拥有什么样的背景。
参考:codeplanet.io
- 调用调用该函数并允许您逐个传递参数。
- 应用调用该函数并允许您将参数作为数组传递。
- 绑定返回一个新的函数,允许你传递一个这个数组和任意数量的参数。
立即调用/应用执行function:
func.call(context, arguments); func.apply(context, [argument1,argument2,..]);
绑定不会立即执行函数,而是返回被包装的应用函数(供以后执行):
function bind(func, context) { return function() { return func.apply(context, arguments); }; }
调用应用并绑定。 以及它们如何不同。
让我们学习呼叫,并使用任何日常术语申请。
你有三辆汽车your_scooter , your_car and your_jet
,它们以相同的机制(方法)开始。 我们用方法push_button_engineStart
创build了一个对象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"); } }
让我们了解什么时候打电话申请使用。 让我们假设你是一名工程师,你有你的your_scooter
, your_car
和your_jet
,它们没有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
正在帮助我们获得使用的方法。
此外,我们使用申请或打电话使用点符号。 automobile.push_button_engineStart.apply()
现在应用并调用接受两个参数。
- 上下文
- 参数
所以这里我们在最后一行代码中设置上下文。
automobile.push_button_engineStart.apply(your_scooter,[20])
call和apply之间的区别就在于,apply以数组的forms接受参数,而call只能接受以逗号分隔的参数列表。
什么是JS绑定function?
一个绑定函数基本上是绑定一些东西的上下文,然后将其存储到一个variables中,以便在稍后阶段执行。
让我们先前的例子更好。 早些时候,我们使用属于汽车对象的方法,并使用它来装备your_car, your_jet and your_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);
还不满意?
让我们把它弄清楚为泪滴。 有时间做实验。 我们将返callback用并应用函数应用程序,并尝试存储函数的值作为参考。
下面的实验失败了,因为调用和apply是立即被调用的,因此,我们从来没有进入存储引用的阶段,
var test_function = automobile.push_button_engineStart.apply(your_scooter);
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
想象一下,绑定不可用。 你可以很容易地构build它如下:
var someFunction=... var objToBind=.... var bindHelper = function (someFunction, objToBind) { return function() { someFunction.apply( objToBind, arguments ); }; } bindHelper(arguments);
阅读了关于这些职位的具体细节,应用程序和词法基础知识的大量知识,我注意到了一个值得提及的模式: call()/ bind()的应用程序跟踪分配的最终效果一个原始函数的variables没有显式地返回一个值
function A(arg){ alert(arg); } // side effects only, no return function B(arg){ return arg; } // it does return a value var checkA = A("A_alert"); // left assignment won't be performed var checkB = B("B_return"); // left assignment as expected alert(checkA) // undefined --> no value was returned alert(checkB) // B_return --> as expected *using call()* checkA = function(){ return A("A_alert"); }; // left assignment requires explicitly function checkA(); // A_alert **using bind()** checkA = A("A_alert").bind(window); // left assignment don't checkA(); // A_alert
bind()'预先打包'一个函数并返回这个函数,call()只执行调用,
我认为它们是相同的地方:它们都可以改变这个函数的值。它们的不同之处在于:bind函数会返回一个新的函数, 调用和apply方法将立即执行该函数,但是apply可以接受一个数组作为参数,它将parsing分离的数组。而且,bind函数可以是Currying。
当我们想要为特定的上下文分配一个函数时,绑定函数应该被使用。
var demo = { getValue : function(){ console.log('demo object get value function') } setValue : function(){ setTimeout(this.getValue.bind(this),1000) } }
在上面的例子中,如果我们调用demo.setValue()函数并直接传递this.getValue函数,那么它不会直接调用demo.setValue函数,因为setTimeout中的this指向窗口对象,所以我们需要将demo对象上下文传递给this.getValue函数使用绑定。 这意味着我们只是通过演示对象的上下文而不是实际调用函数来传递函数。
希望你明白。
欲了解更多信息请参阅详细了解JavaScript绑定function