JavaScript de llamada() y apply() vs bind()?
javascript this (16)
Ya sé que apply
y call
son funciones similares que configuran this
(contexto de una función).
La diferencia está en la forma en que enviamos los argumentos (manual vs array)
Pregunta:
Pero, ¿cuándo debo usar el método 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));
Responda en la forma más simple
- La llamada invoca la función y le permite pasar los argumentos uno por uno.
- Aplicar invoca la función y le permite pasar argumentos como una matriz.
- Bind devuelve una nueva función, lo que le permite pasar a esta matriz y cualquier número de argumentos.
Ejemplos de aplicación frente a llamada frente a enlace
Llamada
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
Aplicar
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
Enlazar
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
Cuándo usar cada
Llamar y solicitar son bastante intercambiables. Simplemente decida si es más fácil enviar una matriz o una lista de argumentos separados por comas.
Siempre recuerdo cuál es cuál al recordar que Llamada es para coma (lista separada) y Aplicar es para Array.
Bind es un poco diferente. Devuelve una nueva función. Llamar y aplicar ejecutan la función actual inmediatamente.
Bind es genial para muchas cosas. Podemos usarlo para curry funciones como en el ejemplo anterior. Podemos tomar una función de saludo simple y convertirla en un saludo o un saludo. También podemos usarlo para eventos como onClick donde no sabemos cuándo serán despedidos, pero sabemos qué contexto queremos que tengan.
Aquí hay un buen artículo para ilustrar la diferencia entre bind()
, apply()
y call()
, resúmalo de la siguiente manera.
bind()
nos permite establecer fácilmente qué objeto específico estará vinculado a esto cuando se invoca una función o método.// 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()
nos permite tomar prestados métodos// 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
Un problema con este ejemplo es que estamos agregando un nuevo método
showData
en el objetocars
y es posible que no queramos hacerlo solo para tomar prestado un método porque el objeto cars ya podría tener una propiedad o nombre de métodoshowData
. No queremos sobrescribirlo accidentalmente. Como veremos en nuestra discusión deApply
yCall
continuación, es mejor pedir prestado un método utilizando el métodoApply
oCall
.bind()
nos permite curry una funciónLa función Currying , también conocida como aplicación de función parcial , es el uso de una función (que acepta uno o más argumentos) que devuelve una nueva función con algunos de los argumentos ya establecidos.
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 + "."; } }
Podemos usar
bind()
para curry esta función degreet
.// 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()
ocall()
para establecer este valor.Los métodos de
apply
,call
ybind
se utilizan para establecer este valor cuando se invoca un método, y lo hacen de formas ligeramente diferentes para permitir el control directo y la versatilidad en nuestro código JavaScript.Los métodos de
apply
ycall
son casi idénticos al configurar este valor, excepto que pasa los parámetros de la función aapply ()
como una matriz , mientras que tiene que enumerar los parámetros individualmente para pasarlos al métodocall ()
.Aquí hay un ejemplo para usar
call
oapply
para configurar esto en la función de devolución de llamada.// 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
Funciones de préstamo con
apply
ocall
Métodos de la matriz de préstamo
Vamos a crear un objeto
array-like
unaarray-like
y tomar prestados algunos métodos de matriz para operar en nuestro objeto similar a una matriz.// 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
Otro caso común es que los
arguments
conversión a la matriz de la siguiente manera// 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"]
Pedir prestado otros metodos
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()
para ejecutar la función de aridad variable
El Math.max
es un ejemplo de función de variable-aridad,
// We can pass any number of arguments to the Math.max () method
console.log (Math.max (23, 11, 34, 56)); // 56
¿Pero qué pasa si tenemos una serie de números para pasar a Math.max
? No podemos hacer esto:
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
Aquí es donde el método apply ()
nos ayuda a ejecutar funciones variadic . En lugar de lo anterior, tenemos que pasar la matriz de números usando apply (
), por lo tanto:
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
Creo que los mismos lugares de ellos son: todos ellos pueden cambiar el valor de esta función. Las diferencias entre ellos son: la función de vinculación devolverá una nueva función como resultado; los métodos de llamada y aplicación ejecutarán la función inmediatamente, pero la aplicación puede aceptar una matriz como parámetros, y analizará la matriz separada. Además, la función de vinculación puede ser Currying.
Imagina, el enlace no está disponible. Se puede construir fácilmente de la siguiente manera:
var someFunction=...
var objToBind=....
var bindHelper = function (someFunction, objToBind) {
return function() {
someFunction.apply( objToBind, arguments );
};
}
bindHelper(arguments);
Permite establecer el valor para this
independientemente de cómo se llame la función. Esto es muy útil cuando se trabaja con devoluciones de llamada:
function sayHello(){
alert(this.message);
}
var obj = {
message : "hello"
};
setTimeout(sayHello.bind(obj), 1000);
Para lograr el mismo resultado con call
se vería así:
function sayHello(){
alert(this.message);
}
var obj = {
message : "hello"
};
setTimeout(function(){sayHello.call(obj)}, 1000);
Supongamos que tenemos función de multiplication
function multiplication(a,b){
console.log(a*b);
}
Permite crear algunas funciones estándar usando bind
var multiby2 = multiplication.bind(this,2);
Ahora multiby2 (b) es igual a la multiplicación (2, b);
multiby2(3); //6
multiby2(4); //8
¿Qué pasa si paso ambos parámetros en enlace
var getSixAlways = multiplication.bind(this,3,2);
Ahora getSixAlways () es igual a la multiplicación (3,2);
getSixAlways();//6
incluso pasando el parámetro devuelve 6; getSixAlways(12); //6
var magicMultiplication = multiplication.bind(this);
Esto crea una nueva función de multiplicación y la asigna a magicMultiplication.
Oh no, estamos ocultando la funcionalidad de multiplicación en magicMultiplication.
llamando a magicMultiplication
devuelve una function b()
blanco function b()
en ejecución funciona bien magicMultiplication(6,5); //30
magicMultiplication(6,5); //30
¿Qué hay de llamar y aplicar?
magicMultiplication.call(this,3,2); //6
magicMultiplication.apply(this,[5,2]); //10
En palabras simples, bind
crea la función, call
y apply
ejecuta la función mientras que apply
espera los parámetros en la matriz
Tanto Function.prototype.call()
como Function.prototype.apply()
llaman a una función con un valor dado y devuelven el valor de retorno de esa función.
Function.prototype.bind()
, por otro lado, crea una nueva función con un valor dado y devuelve esa función sin ejecutarla.
Por lo tanto, vamos a tomar una función que se parece a esto:
var logProp = function(prop) {
console.log(this[prop]);
};
Ahora, tomemos un objeto que se ve así:
var Obj = {
x : 5,
y : 10
};
Podemos unir nuestra función a nuestro objeto de esta manera:
Obj.log = logProp.bind(Obj);
Ahora, podemos ejecutar Obj.log
en cualquier lugar de nuestro código:
Obj.log(''x''); // Output : 5
Obj.log(''y''); // Output : 10
Donde realmente se pone interesante, es cuando no solo vincula un valor para this
, sino también para su argumento prop
:
Obj.logX = logProp.bind(Obj, ''x'');
Obj.logY = logProp.bind(Obj, ''y'');
Ahora podemos hacer esto:
Obj.logX(); // Output : 5
Obj.logY(); // Output : 10
Todos adjuntan esto a la función (u objeto) y la diferencia está en la invocación de la función (ver más abajo).
la llamada adjunta esto a la función y ejecuta la función inmediatamente:
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 adjunta esto a la función y debe invocarse por separado de esta manera:
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"
o así:
...
var helloFunc = person.hello.bind({ name: "Jim Smith" }, "world");
helloFunc(); // output: Jim Smith says hello world"
La aplicación es similar a la llamada, excepto que toma un objeto similar a una matriz en lugar de enumerar los argumentos uno por uno:
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"
Use .bind()
cuando desee que esa función se llame más tarde con un contexto determinado, útil en eventos. Utilice .call()
o .apply()
cuando desee invocar la función inmediatamente, y modifique el contexto.
Llamar / aplicar llamar a la función inmediatamente, mientras que bind
devuelve una función que, una vez ejecutada posteriormente, tendrá el contexto correcto configurado para llamar a la función original. De esta manera puede mantener el contexto en devoluciones de llamada asíncronas y eventos.
Lo hago mucho:
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.
};
Lo uso ampliamente en Node.js para las devoluciones de llamadas asíncronas para las que deseo pasar un método miembro, pero aún quiero que el contexto sea la instancia que inició la acción asíncrona.
Una implementación simple e ingenua de bind sería como:
Function.prototype.bind = function(ctx) {
var fn = this;
return function() {
fn.apply(ctx, arguments);
};
};
Hay más en esto (como pasar otros argumentos), pero puede leer más sobre él y ver la implementación real bind .
Espero que esto ayude.
la función de vinculación debe usarse cuando queremos asignar una función con un contexto particular para, por ejemplo,
var demo = {
getValue : function(){
console.log(''demo object get value function'')
}
setValue : function(){
setTimeout(this.getValue.bind(this),1000)
}
}
en el ejemplo anterior, si llamamos a la función demo.setValue () y pasamos directamente a esta función.getValue, entonces no llamamos directamente a la función demo.setValue porque esto en setTimeout se refiere al objeto de la ventana, por lo que necesitamos pasar el contexto del objeto de demostración a este.getValue función mediante enlace. Significa que solo pasamos la función con el contexto del objeto de demostración que no llama a la función de manera actully.
Espero que entiendas .
para obtener más información, consulte la función de enlace de javascript saber en detalle
La función call / apply ejecuta inmediatamente:
func.call(context, arguments);
func.apply(context, [argument1,argument2,..]);
bind no ejecuta la función de forma inmediata, pero devuelve la función de aplicación de reinicio (para una ejecución posterior):
function bind(func, context) {
return function() {
return func.apply(context, arguments);
};
}
Llame a aplicar y enlazar. Y como son diferentes.
Permite aprender llamar y aplicar utilizando cualquier terminología diaria.
Tiene tres automóviles: your_scooter , your_car and your_jet
que comienzan con el mismo mecanismo (método). Creamos un objeto automobile
con un método 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");
}
}
Vamos a entender cuándo se usa y se llama. Supongamos que usted es un ingeniero y tiene your_scooter
, your_car
y your_jet
que no vino con un push_button_engine_start y desea utilizar un tercero push_button_engineStart
.
Si ejecuta las siguientes líneas de código, darán un error. ¿POR QUÉ?
//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);
Así que el ejemplo anterior es exitoso y le da a su_scooter, su_car, su_jeto una característica del objeto del automóvil.
Vamos a profundizar aquí Aquí dividiremos la línea de código anterior. automobile.push_button_engineStart
nos está ayudando a obtener el método que se está utilizando.
Además utilizamos aplicar o llamar usando la notación de puntos. automobile.push_button_engineStart.apply()
Ahora aplique y llame a aceptar dos parámetros.
- contexto
- argumentos
Así que aquí establecemos el contexto en la última línea de código.
automobile.push_button_engineStart.apply(your_scooter,[20])
La diferencia entre call y apply es que solo se aplican los parámetros aceptables en forma de una matriz, mientras que call simplemente puede aceptar una lista de argumentos separados por comas.
¿Qué es la función JS Bind?
Una función de enlace es básicamente la que enlaza el contexto de algo y luego lo almacena en una variable para su ejecución en una etapa posterior.
Hagamos nuestro ejemplo anterior aún mejor. Anteriormente, utilizamos un método que pertenece al objeto del automóvil y lo usamos para equipar your_car, your_jet and your_scooter
. Ahora imaginemos que queremos dar un push_button_engineStart
separado para arrancar nuestros automóviles individualmente en cualquier etapa posterior de la ejecución que deseemos.
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);
todavia no esta satisfecho?
Vamos a dejarlo claro como lágrima. Tiempo para experimentar. Volveremos a llamar y aplicar la aplicación de función e intentaremos almacenar el valor de la función como referencia.
El siguiente experimento falla porque la llamada y la aplicación se invocan de inmediato, por lo tanto, nunca llegamos a la etapa de almacenar una referencia en una variable que es donde la función de vinculación roba el espectáculo.
var test_function = automobile.push_button_engineStart.apply(your_scooter);
bind : Enlaza la función con el valor y el contexto proporcionados, pero no ejecuta la función. Para ejecutar la función necesitas llamar a la función.
llamada : Ejecuta la función con el contexto y parámetro provistos.
apply : Ejecuta la función con el contexto proporcionado y el parámetro como matriz .
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;
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
- La llamada invoca la función y le permite pasar los argumentos uno por uno.
- Aplicar invoca la función y le permite pasar argumentos como una matriz.
- Bind devuelve una nueva función, lo que le permite pasar a esta matriz y cualquier número de argumentos.