¿Para qué sirve el método de 'vinculación' de JavaScript?


651

¿Para qué sirve bind()JavaScript?


8
Mi caso de uso estándar:select = document.querySelector.bind(document)
abandono el

1
^ Y para cualquiera que se pregunte, la razón que se necesita es porque de thislo contrario se referiría al windowobjeto global. Con document.querySelector.bind(document), nos aseguramos de que select's thisse refiere a document, y no a window. Sin embargo, alguien me corrige si entendí mal eso.
AleksandrH

Respuestas:


614

Bind crea una nueva función que forzará al thisinterior de la función a ser el parámetro pasado bind().

Aquí hay un ejemplo que muestra cómo usar bindpara pasar un método miembro que tiene el correcto this:

var myButton = {
  content: 'OK',
  click() {
    console.log(this.content + ' clicked');
  }
};

myButton.click();

var looseClick = myButton.click;
looseClick(); // not bound, 'this' is not myButton - it is the globalThis

var boundClick = myButton.click.bind(myButton);
boundClick(); // bound, 'this' is myButton

Que imprime:

OK clicked
undefined clicked
OK clicked

También puede agregar parámetros adicionales después del primer thisparámetro ( ) y bindpasará esos valores a la función original. Cualquier parámetro adicional que luego pase a la función enlazada se pasará después de los parámetros enlazados:

// Example showing binding some parameters
var sum = function(a, b) {
  return a + b;
};

var add5 = sum.bind(null, 5);
console.log(add5(10));

Que imprime:

15

Consulte la función de enlace de JavaScript para obtener más información y ejemplos interactivos.

Actualización: ECMAScript 2015 agrega soporte para =>funciones. =>Las funciones son más compactas y no cambian el thispuntero de su ámbito de definición, por lo que es posible que no necesite usar con bind()tanta frecuencia. Por ejemplo, si desea una función activada Buttondesde el primer ejemplo para conectar la clickdevolución de llamada a un evento DOM, las siguientes son formas válidas de hacerlo:

var myButton = {
  ... // As above
  hookEvent(element) {
    // Use bind() to ensure 'this' is the 'this' inside click()
    element.addEventListener('click', this.click.bind(this));
  }
};

O:

var myButton = {
  ... // As above
  hookEvent(element) {
    // Use a new variable for 'this' since 'this' inside the function
    // will not be the 'this' inside hookEvent()
    var me = this;
    element.addEventListener('click', function() { me.click() });
  }
};    

O:

var myButton = {
  ... // As above
  hookEvent(element) {
    // => functions do not change 'this', so you can use it directly
    element.addEventListener('click', () => this.click());
  }
};

66
Excelente explicación, pero estoy luchando por encontrar ejemplos en los que me gustaría usar la tercera opción que describiste en lugar de la primera opción. ¿Puede describir situaciones en las que sintió la necesidad de utilizar la tercera opción?
Darryl

55
No creo que alguna vez haya usado bind que no sea para enlazar 'this'. La otra forma se conoce como Aplicación parcial y es bastante común en lenguajes funcionales. Me imagino que está incluido para completar.
nkron

43
En caso de que alguien se pregunte por qué looseClick () no está vinculado a myButton, es porque "esto" se refiere al objeto que invoca la función (looseClick ()). El objeto que invoca looseClick () es el objeto global.
pokero

44
@Darryl: una de las razones sería pasar parámetros de los controladores de eventos. Si tiene este código de reacción: var Note = React.createClass({ add: function(text){ ... }, render: function () { return <button onClick={this.add.bind(null, "New Note")}/> } }cuando haga clic en el botón, pasará un texto de parámetro "Nueva nota" al addmétodo.
P. Myer Nore

2
"También puede agregar parámetros adicionales después del primer parámetro y el enlace pasará esos valores a la función original antes de pasar los parámetros adicionales que pase a la función enlazada:" Esta redacción es confusa.
Ken Ingram

271

El uso más simple de bind()es hacer una función que, sin importar cómo se llame, se llame con un thisvalor particular .

x = 9;
var module = {
    x: 81,
    getX: function () {
        return this.x;
    }
};

module.getX(); // 81

var getX = module.getX;
getX(); // 9, because in this case, "this" refers to the global object

// create a new function with 'this' bound to module
var boundGetX = getX.bind(module);
boundGetX(); // 81

Por favor consulte este enlace para más información

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind


38
La mejor introducción a bind () que he visto.
thomasfl

3
Gran respuesta, ya que su ejemplo no requiere conocimiento sobre las características del lenguaje (por ejemplo prototype) que pueden ser nuevas para los principiantes.
Edward

1
sucinto y muy claro!
papigee

172

la unión permite

  • establece el valor de "esto" en un objeto específico. Esto se vuelve muy útil ya que a veces esto no es lo que se pretende.
  • reutilizar métodos
  • curry una función

Por ejemplo, tiene una función para deducir las tarifas mensuales del club

function getMonthlyFee(fee){
  var remaining = this.total - fee;
  this.total = remaining;
  return this.name +' remaining balance:'+remaining;
}

Ahora desea reutilizar esta función para un miembro diferente del club. Tenga en cuenta que la tarifa mensual variará de un miembro a otro.

Imaginemos que Rachel tiene un saldo de 500 y una cuota de membresía mensual de 90.

var rachel = {name:'Rachel Green', total:500};

Ahora, cree una función que pueda usarse una y otra vez para deducir la tarifa de su cuenta todos los meses

//bind
var getRachelFee = getMonthlyFee.bind(rachel, 90);
//deduct
getRachelFee();//Rachel Green remaining balance:410
getRachelFee();//Rachel Green remaining balance:320

Ahora, la misma función getMonthlyFee podría usarse para otro miembro con una tarifa de membresía diferente. Por ejemplo, Ross Geller tiene un saldo de 250 y una tarifa mensual de 25

var ross = {name:'Ross Geller', total:250};
//bind
var getRossFee = getMonthlyFee.bind(ross, 25);
//deduct
getRossFee(); //Ross Geller remaining balance:225
getRossFee(); //Ross Geller remaining balance:200

99
En su ejemplo, creo que me inclinaría a configurar un objeto miembro instanciado con la nueva palabra clave donde cada miembro tenía sus propias propiedades / métodos. Entonces es simplemente una cuestión de ross.getMonthlyFee (25). ¿Fue este ejemplo solo para demostrar el uso de bind (), o hay alguna ventaja en su enfoque?
Darryl

Me encanta el curry una función!
Jerry Liu

no lo sé, pero haría var getRachelFee = getMonthlyFee (rachel, 90); Y la función sería function getMonthlyFee (member, fee) {} algo similar.
Miguel

1
@KhanSharp Su respuesta es correcta, pero son sus referencias a la serie de televisión Friends me hace comentar y votar. Gracias por tu respuesta 🤗.
Saurabh Lende

79

De los documentos de MDN en Function.prototype.bind():

El método bind () crea una nueva función que, cuando se llama, tiene esta palabra clave establecida en el valor proporcionado, con una secuencia dada de argumentos que precede a cualquier proporcionada cuando se llama a la nueva función.

¡¿Entonces que significa eso?!

Bueno, tomemos una función que se vea así:

var logProp = function(prop) {
    console.log(this[prop]);
};

Ahora, tomemos un objeto que se vea así:

var Obj = {
    x : 5,
    y : 10
};

Podemos vincular nuestra función a nuestro objeto de esta manera:

Obj.log = logProp.bind(Obj);

Ahora, podemos ejecutar Obj.logen cualquier parte de nuestro código:

Obj.log('x'); // Output : 5
Obj.log('y'); // Output : 10

Esto funciona porque vinculamos el valor de thisnuestro objeto Obj.


Donde realmente se pone interesante, es cuando no solo unes un valor this, sino también 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

A diferencia de Obj.log, no tenemos que pasar xo y, porque pasamos esos valores cuando hicimos nuestro enlace.


99
Esta respuesta debería recibir más amor. Bien explicado.
Chax

Muy buena combinación de visión general y ejemplo específico.
Ken Ingram

¿Dónde está el botón que dispara 100 ups rectos?
kushalvm

Con esto, también recomendaría leer la sección de documentos MDN de las funciones aplicadas parcialmente para comprender el uso del enlace "nulo". Debería cerrar las puertas para la mayoría del uso de enlace. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
kushalvm

23

Las variables tienen ámbitos locales y globales. Supongamos que tenemos dos variables con el mismo nombre. Uno está definido globalmente y el otro está definido dentro del cierre de una función y queremos obtener el valor variable que está dentro del cierre de la función. En ese caso usamos este método bind (). Por favor vea el ejemplo simple a continuación:

var x = 9; // this refers to global "window" object here in the browser
var person = {
  x: 81,
  getX: function() {
    return this.x;
  }
};

var y = person.getX; // It will return 9, because it will call global value of x(var x=9).

var x2 = y.bind(person); // It will return 81, because it will call local value of x, which is defined in the object called person(x=81).

document.getElementById("demo1").innerHTML = y();
document.getElementById("demo2").innerHTML = x2();
<p id="demo1">0</p>
<p id="demo2">0</p>


18

Resumen:

El bind()método toma un objeto como primer argumento y crea una nueva función. Cuando se invoca la función, el valor de thisen el cuerpo de la función será el objeto que se pasó como argumento en la bind()función.

Cómo this funciona en JS de todos modos?

El valor de thisen javascript depende siempre de qué objeto se llama la función. El valor de esto siempre se refiere al objeto a la izquierda del punto desde donde se llama la función . En el caso del alcance global esto es window(o globalen nodeJS). Solo call, applyy bindpuede alterar este enlace de manera diferente. Aquí hay un ejemplo para mostrar cómo funciona esta palabra clave:

let obj = {
  prop1: 1,
  func: function () { console.log(this); } 
}

obj.func();   // obj left of the dot so this refers to obj

const customFunc = obj.func;  // we store the function in the customFunc obj

customFunc();  // now the object left of the dot is window, 
               // customFunc() is shorthand for window.customFunc()
               // Therefore window will be logged

¿Cómo se usa bind?

Bind puede ayudar a superar las dificultades con la thispalabra clave al tener un objeto fijo al que thisse referirá. Por ejemplo:

var name = 'globalName';

const obj = {
  name: 'myName',
  sayName: function () { console.log(this.name);}
}

const say = obj.sayName; // we are merely storing the function the value of this isn't magically transferred

say(); // now because this function is executed in global scope this will refer to the global var

const boundSay = obj.sayName.bind(obj); // now the value of this is bound to the obj object

boundSay();  // Now this will refer to the name in the obj object: 'myName'

Una vez que la función está vinculada a un thisvalor particular , podemos pasarla e incluso ponerla en propiedades de otros objetos. El valor de thisseguirá siendo el mismo.


3
Sus comentarios en su código sobre objes el objeto porque está a la izquierda del punto y windowes el objeto porque es la abreviatura window.custFunc()y la windowizquierda del punto fue muy perspicaz para mí.
nzaleski el

12

Explicaré el enlace teóricamente y prácticamente

enlazar en javascript es un método: Function.prototype.bind. Bind es un método. Se llama prototipo de función. Este método crea una función cuyo cuerpo es similar a la función en la que se llama, pero 'this' se refiere al primer parámetro pasado al método de enlace. Su sintaxis es

     var bindedFunc = Func.bind(thisObj,optionsArg1,optionalArg2,optionalArg3,...);

Ejemplo:--

  var checkRange = function(value){
      if(typeof value !== "number"){
              return false;
      }
      else {
         return value >= this.minimum && value <= this.maximum;
      }
  }

  var range = {minimum:10,maximum:20};

  var boundedFunc = checkRange.bind(range); //bounded Function. this refers to range
  var result = boundedFunc(15); //passing value
  console.log(result) // will give true;

Básicamente convierte cualquier 'esto' dentro de la función en cualquier objeto que pases, ¿correcto?
Harvey Lin

11

El método bind () crea una nueva instancia de función cuyo valor está vinculado al valor que se pasó a bind (). Por ejemplo:

   window.color = "red"; 
   var o = { color: "blue" }; 
   function sayColor(){ 
       alert(this.color); 
   } 
   var objectSayColor = sayColor.bind(o); 
   objectSayColor(); //blue 

Aquí, se crea una nueva función llamada objectSayColor () a partir de sayColor () llamando a bind () y pasando el objeto o. La función objectSayColor () tiene un valor equivalente a o, por lo que llamar a la función, incluso como una llamada global, da como resultado que se muestre la cadena "azul".

Referencia: Nicholas C. Zakas - JAVASCRIPT® PROFESIONAL PARA DESARROLLADORES WEB


ejemplo conciso y lacónico
Ahmad Sharif

9

Crear una nueva función uniendo argumentos a valores

El bindmétodo crea una nueva función a partir de otra función con uno o más argumentos vinculados a valores específicos, incluido el thisargumento implícito .

Aplicación parcial

Este es un ejemplo de aplicación parcial . Normalmente suministramos una función con todos sus argumentos que produce un valor. Esto se conoce como aplicación de función. Estamos aplicando la función a sus argumentos.

Una función de orden superior (HOF)

La aplicación parcial es un ejemplo de una función de orden superior (HOF) porque produce una nueva función con un menor número de argumentos.

Vinculando múltiples argumentos

Puede usar bindpara transformar funciones con múltiples argumentos en nuevas funciones.

function multiply(x, y) { 
    return x * y; 
}

let multiplyBy10 = multiply.bind(null, 10);
console.log(multiplyBy10(5));

Conversión de método de instancia a función estática

En el caso de uso más común, cuando se llama con un argumento, el bindmétodo creará una nueva función que tiene el thisvalor vinculado a un valor específico. En efecto, esto transforma un método de instancia en un método estático.

function Multiplier(factor) { 
    this.factor = factor;
}

Multiplier.prototype.multiply = function(x) { 
    return this.factor * x; 
}

function ApplyFunction(func, value) {
    return func(value);
}

var mul = new Multiplier(5);

// Produces garbage (NaN) because multiplying "undefined" by 10
console.log(ApplyFunction(mul.multiply, 10));

// Produces expected result: 50
console.log(ApplyFunction(mul.multiply.bind(mul), 10));

Implementación de una devolución de llamada con estado

El siguiente ejemplo muestra cómo usar el enlace de thispuede permitir que un método de objeto actúe como una devolución de llamada que puede actualizar fácilmente el estado de un objeto.

function ButtonPressedLogger()
{
   this.count = 0;
   this.onPressed = function() {
      this.count++;
      console.log("pressed a button " + this.count + " times");
   }
   for (let d of document.getElementsByTagName("button"))
      d.onclick = this.onPressed.bind(this);
}

new ButtonPressedLogger();      
<button>press me</button>
<button>no press me</button>


6

Como se mencionó, le Function.bind()permite especificar el contexto en el que se ejecutará la función (es decir, le permite pasar en qué objeto thisse resolverá la palabra clave en el cuerpo de la función.

Un par de métodos de API de kit de herramientas análogos que realizan un servicio similar:

jQuery.proxy ()

Dojo.hitch ()


3
/**
 * Bind is a method inherited from Function.prototype same like call and apply
 * It basically helps to bind a function to an object's context during initialisation 
 * 
 * */

window.myname = "Jineesh";  
var foo = function(){ 
  return this.myname;
};

//IE < 8 has issues with this, supported in ecmascript 5
var obj = { 
    myname : "John", 
    fn:foo.bind(window)// binds to window object
}; 
console.log( obj.fn() ); // Returns Jineesh

3

Considere el programa simple que se detalla a continuación,

//we create object user
let User = { name: 'Justin' };

//a Hello Function is created to Alert the object User 
function Hello() {
  alert(this.name);
}

//since there the value of this is lost we need to bind user to use this keyword
let user = Hello.bind(User);
user();

//we create an instance to refer the this keyword (this.name);

2

La función de vinculación crea una nueva función con el mismo cuerpo de función que la función a la que está llamando. Se llama con este argumento. ¿Por qué utilizamos la diversión de vinculación? : cuando cada vez que se crea una nueva instancia y tenemos que usar la primera instancia inicial, usamos bind fun. No podemos anular la bind fun. simplemente almacena el objeto inicial de la clase.

setInterval(this.animate_to.bind(this), 1000/this.difference);

0

Otro uso es que puede pasar la función enlazada como argumento a otra función que está operando en otro contexto de ejecución.

var name = "sample";
function sample(){
  console.log(this.name);
}
var cb = sample.bind(this);

function somefunction(cb){
  //other code
  cb();
}
somefunction.call({}, cb);

0

Ejemplo simple

function lol(text) {
    console.log(this.name, text);
}

lol(); // undefined undefined
lol('first'); // undefined first
lol.call({name: 'karl'}); // karl undefined
lol.call({name: 'karl'}, 'second'); // karl second
lol.apply({name: 'meg'}); // meg undefined
lol.apply({name: 'meg'}, ['third']); // meg third
const newLol = lol.bind({name: 'bob'});
newLol(); // bob undefined
newLol('fourth'); // bob fourth

0

Método de enlace

Una implementación de enlace podría verse así:

Function.prototype.bind = function () {
  const self = this;
  const args = [...arguments];
  const context = args.shift();

  return function () {
    return self.apply(context, args.concat([...arguments]));
  };
};

La función de vinculación puede tomar cualquier número de argumentos y devolver una nueva función .

La nueva función llamará a la función original usando el Function.prototype.applymétodo JS .
El applymétodo usará el primer argumento pasado a la función de destino como su contexto ( this), y el segundo argumento de matriz del applymétodo será una combinación del resto de los argumentos de la función de destino, concat con los argumentos utilizados para llamar al retorno función (en ese orden).

Un ejemplo puede verse así:

function Fruit(emoji) {
  this.emoji = emoji;
}

Fruit.prototype.show = function () {
  console.log(this.emoji);
};

const apple = new Fruit('🍎');
const orange = new Fruit('🍊');

apple.show();  // 🍎
orange.show(); // 🍊

const fruit1 = apple.show;
const fruit2 = apple.show.bind();
const fruit3 = apple.show.bind(apple);
const fruit4 = apple.show.bind(orange);

fruit1(); // undefined
fruit2(); // undefined
fruit3(); // 🍎
fruit4(); // 🍊


0

Explicación simple:

bind () crea una nueva función, una nueva referencia en una función que le devuelve.

En el parámetro después de esta palabra clave, pasa el parámetro que desea preconfigurar. En realidad no se ejecuta de inmediato, solo se prepara para la ejecución.

Puede preconfigurar tantos parámetros como desee.

Ejemplo simple para entender el enlace:

function calculate(operation) {
  if (operation === 'ADD') {
   alert('The Operation is Addition');
  } else if (operation === 'SUBTRACT') {
   alert('The Operation is Subtraction');
  }
}

addBtn.addEventListener('click', calculate.bind(this, 'ADD'));
subtractBtn.addEventListener('click', calculate.bind(this, 'SUBTRACT'));

-1

bind es una función que está disponible en el prototipo de script java, ya que el nombre sugiere que bind se usa para vincular su llamada de función al contexto con el que esté tratando, por ejemplo:

    var rateOfInterest='4%';
    var axisBank=
    {
    rateOfInterest:'10%',
    getRateOfInterest:function()
    {
    return this.rateOfInterest;
    }
    }
    axisBank.getRateOfInterest() //'10%' 


    let knowAxisBankInterest=axisBank.getRateOfInterest // when you want to assign the function call to a varaible we use this syntax
    knowAxisBankInterest(); // you will get output as '4%' here by default the function is called wrt global context

let knowExactAxisBankInterest=knowAxisBankInterest.bind(axisBank);     //so here we need bind function call  to its local context


    knowExactAxisBankInterest() // '10%' 

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.