Pregunta Javascript call () & apply () vs bind ()?


eso ya lo se apply y call son funciones similares que establecenthis (contexto de una función).

La diferencia es con la forma en que enviamos los argumentos (manual vs array)

Pregunta:

Pero cuando debería usar el bind() método?

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


619
2018-03-16 21:40


origen


Respuestas:


Utilizar .bind() cuando desea que esa función se llame más tarde con un cierto contexto, útil en eventos. Utilizar .call() o .apply() cuando desee invocar la función de inmediato y modificar el contexto.

Llamar / aplicar llamar a la función de inmediato, mientras que bind devuelve una función que, cuando se ejecuta más tarde, tendrá el contexto correcto establecido para llamar a la función original. De esta forma puede mantener el contexto en devoluciones de llamada y eventos asincrónicos.

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 extensamente en Node.js para las devoluciones de llamada asíncronas para las que quiero 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 puedes leer más sobre él y ver la implementación real en el MDN.

Espero que esto ayude.


646
2018-03-16 21:44



Todos ellos se unen esta en la función (u objeto) y la diferencia está en la invocación de la función (ver a continuación).

llamada se adjunta esta en la función y ejecuta la función de inmediato:

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"

enlazar se adjunta esta en 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"

aplicar es parecido a llamada excepto que toma un objeto parecido 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"                                     

365
2017-08-10 14:50



Responda en la forma MÁS SIMPLE

  • 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.
  • Enlazar devuelve una nueva función, lo que le permite pasar un esta matriz y cualquier cantidad de argumentos.

Ejemplos de aplicación frente a llamada contra vinculación

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 aplicar 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 el que al recordar esa llamada es para coma (lista separada) y Aplicar es para matriz.

Bind es un poco diferente. Devuelve una nueva función. Call and Apply ejecuta la función actual inmediatamente.

Bind es ideal para muchas cosas. Podemos usarlo para curry funciones como en el ejemplo anterior. Podemos tomar una función hello simple y convertirla en helloJon o helloKelly. También podemos usarlo para eventos como onClick, donde no sabemos cuándo serán despedidos, pero sabemos qué contexto queremos que tengan.

Referance: codeplanet.io


56
2017-10-12 02:47



Permite establecer el valor para this independiente de cómo se llama 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 callse vería así:

  function sayHello(){
    alert(this.message);
  }

  var obj = {
     message : "hello"
  };
  setTimeout(function(){sayHello.call(obj)}, 1000);

51
2018-03-16 21:45



Supongamos que tenemos multiplication función

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 el enlace?

var getSixAlways = multiplication.bind(this,3,2);

Ahora getSixAlways () es igual a la multiplicación (3,2);

getSixAlways();//6

incluso el parámetro que pasa 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.

vocación magicMultiplication devuelve un espacio en blanco function b()

en ejecución funciona bien magicMultiplication(6,5); //30

¿Qué tal llamar y postularse?

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 apply espera los parámetros en matriz


40
2018-06-10 18:04



Ambos Function.prototype.call() y Function.prototype.apply() llamar a una función con un dado this valor, y devolver el valor de retorno de esa función.

Function.prototype.bind(), por otro lado, crea una nueva función con un dado this valor, y devuelve esa función sin ejecutarlo.

Entonces, tomemos una función que se ve así:

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 correr Obj.log en cualquier parte 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, pero 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

25
2018-01-18 03:59



Aqui hay uno buen artículo para ilustrar la diferencia entre bind(), apply() y call(), resúmalo como abajo.

  • bind() nos permite establecer fácilmente qué objeto específico estará obligado a esta 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() permitirnos 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 sobre el cars objeto y es posible que no deseemos hacer eso solo para tomar prestado un método porque el objeto de autos ya puede tener una propiedad o nombre de método showData. No queremos sobrescribirlo accidentalmente. Como veremos en nuestra discusión de Apply y Call abajo, lo mejor es pedir prestado un método utilizando cualquiera de los Apply o Call método.

  • bind() nos permite curry una función

    Función de currying, también conocido como aplicación de función parcial, es el uso de un 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 + ".";
        }
     }
    

    Nosotros podemos usar bind() para curry greet función

    // 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() o call() para establecer esta valor

    los apply, cally bind todos los métodos se utilizan para establecer este valor cuando se invoca un método, y lo hacen en un poco diferentes formas de permitir el uso de control directo y versatilidad en nuestro código JavaScript.

    los apply y call los métodos son casi idénticos al establecer este valor, excepto que pasa los parámetros de la función a apply () como una matriz, mientras que tienes que enumera los parámetros individualmente pasarlos a la call () método.

    Aquí hay un ejemplo para usar call o apply para establecer esta 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
    
  • Préstamo de funciones con apply o call

    • Métodos Borrow Array

      Vamos a crear un array-like Objeto y prestado 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 convertir arguments organizar como sigue

        // 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 métodos

      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​
      
  • Utilizar apply() ejecutar variable-arity función

los Math.max es un ejemplo de función de aria variable,

// We can pass any number of arguments to the Math.max () method​
console.log (Math.max (23, 11, 34, 56)); // 56

Pero, ¿y 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 apply () método nos ayuda a ejecutar funciones variadas. En lugar de lo anterior, tenemos que pasar la matriz de números usando apply () así:

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

13
2018-04-08 06:45