los bind() El método crea una nueva función que, cuando se llama, tiene su this palabra clave establecida en el valor proporcionado, con una secuencia dada de argumentos que preceden a los proporcionados cuando se llama a la nueva función.

Sintaxis

bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, ... , argN)

Parámetros

thisArg
El valor que se pasará como this parámetro a la función de destino func cuando se llama a la función vinculada. El valor se ignora si la función vinculada se construye utilizando el new operador. Cuando usas bind para crear una función (suministrada como devolución de llamada) dentro de un setTimeout, cualquier valor primitivo pasado como thisArg se convierte en objeto. Si no se proporcionan argumentos para bind , o si el thisArg es null o undefined, los this del alcance de ejecución se trata como el thisArg para la nueva función.
arg1, arg2, ...argN Opcional
Argumentos para anteponer a los argumentos proporcionados a la función vinculada al invocar func.

Valor devuelto

Una copia de la función dada con el especificado this valor y argumentos iniciales (si se proporcionan).

Descripción

los bind() función crea un nuevo función vinculada, que es un objeto de función exótica (un término de ECMAScript 2015) que envuelve el objeto de función original. Llamar a la función enlazada generalmente da como resultado la ejecución de su función envuelta.

Una función vinculada tiene las siguientes propiedades internas:

[[BoundTargetFunction]]
El objeto de función envuelto
[[BoundThis]]
El valor que siempre se pasa como this valor al llamar a la función envuelta.
[[BoundArguments]]
Una lista de valores cuyos elementos se utilizan como los primeros argumentos para cualquier llamada a la función envuelta.
[[Call]]
Ejecuta código asociado con este objeto. Se invoca mediante una expresión de llamada a función. Los argumentos del método interno son un this value y una lista que contiene los argumentos pasados ​​a la función por una expresión de llamada.

Cuando se llama a una función vinculada, llama al método interno [[Call]] sobre [[BoundTargetFunction]], con los siguientes argumentos Call(boundThis, ...args). Dónde boundThis es [[BoundThis]], args es [[BoundArguments]], seguido de los argumentos pasados ​​por la llamada a la función.

Una función ligada también se puede construir usando el new operador. Hacerlo actúa como si la función de destino se hubiera construido. El proporcionado this value se ignora, mientras que los argumentos antepuestos se proporcionan a la función emulada.

Ejemplos de

Creando una función enlazada

El uso más simple de bind() es hacer una función que, no importa cómo se llame, se llame con un particular this valor.

Un error común para los nuevos programadores de JavaScript es extraer un método de un objeto, luego llamar a esa función y esperar que use el objeto original como su this (por ejemplo, utilizando el método en código basado en devolución de llamada).

Sin embargo, sin un cuidado especial, el objeto original suele perderse. La creación de una función vinculada a partir de la función, utilizando el objeto original, resuelve perfectamente este problema:

this.x = 9;    // 'this' refers to global 'window' object here in a browser
const module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX();
//  returns 81

const retrieveX = module.getX;
retrieveX();
//  returns 9; the function gets invoked at the global scope

//  Create a new function with 'this' bound to module
//  New programmers might confuse the
//  global variable 'x' with module's property 'x'
const boundGetX = retrieveX.bind(module);
boundGetX();
//  returns 81

Funciones parcialmente aplicadas

El siguiente uso más simple de bind() es hacer una función con argumentos iniciales preespecificados.

Estos argumentos (si los hay) siguen los this value y luego se insertan al comienzo de los argumentos que se pasan a la función de destino, seguidos de los argumentos que se pasan a la función vinculada en el momento en que se llama.

function list() {
  return Array.prototype.slice.call(arguments);
}

function addArguments(arg1, arg2) {
  return arg1 + arg2
}

const list1 = list(1, 2, 3);
//  [1, 2, 3]

const result1 = addArguments(1, 2);
//  3

// Create a function with a preset leading argument
const leadingThirtysevenList = list.bind(null, 37);

// Create a function with a preset first argument.
const addThirtySeven = addArguments.bind(null, 37);

const list2 = leadingThirtysevenList();
//  [37]

const list3 = leadingThirtysevenList(1, 2, 3);
//  [37, 1, 2, 3]

const result2 = addThirtySeven(5);
//  37 + 5 = 42

const result3 = addThirtySeven(5, 10);
//  37 + 5 = 42
//  (the second argument is ignored)

Con setTimeout()

Por defecto dentro de window.setTimeout(), los this la palabra clave se establecerá en el window (o global) objeto. Cuando se trabaja con métodos de clase que requieren this para hacer referencia a instancias de clase, puede vincular explícitamente this a la función de devolución de llamada, para mantener la instancia.

function LateBloomer() {
  this.petalCount = Math.floor(Math.random() * 12) + 1;
}

// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log(`I am a beautiful flower with ${this.petalCount} petals!`);
};

const flower = new LateBloomer();
flower.bloom();
//  after 1 second, calls 'flower.declare()'

Funciones enlazadas utilizadas como constructores

Advertencia: Esta sección demuestra las capacidades de JavaScript y documenta algunos casos extremos de la bind() método.

Los métodos que se muestran a continuación no son la mejor manera de hacer las cosas y probablemente no deberían usarse en ningún entorno de producción.

Las funciones enlazadas son automáticamente adecuadas para su uso con new operador para construir nuevas instancias creadas por la función de destino. Cuando se usa una función vinculada para construir un valor, el this se ignora.

Sin embargo, los argumentos proporcionados todavía se anteponen a la llamada al constructor:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function() {
  return `${this.x},${this.y}`;
};

const p = new Point(1, 2);
p.toString();
// '1,2'

//  not supported in the polyfill below,

//  works fine with native bind:

const YAxisPoint = Point.bind(null, 0/*x*/);

const emptyObj = {};
const YAxisPoint = Point.bind(emptyObj, 0/*x*/);

const axisPoint = new YAxisPoint(5);
axisPoint.toString();                    // '0,5'

axisPoint instanceof Point;              // true
axisPoint instanceof YAxisPoint;         // true
new YAxisPoint(17, 42) instanceof Point; // true

Tenga en cuenta que no necesita hacer nada especial para crear una función vinculada para usar con new.

El corolario es que no necesita hacer nada especial para crear una función enlazada que se llamará claramente, incluso si prefiere requerir que la función enlazada solo se llame usando new.

//  Example can be run directly in your JavaScript console
//  ...continued from above

//  Can still be called as a normal function
//  (although usually this is undesired)
YAxisPoint(13);

`${emptyObj.x},${emptyObj.y}`;
// >  '0,13'

Si desea admitir el uso de una función vinculada solo usando new, o solo llamándolo, la función de destino debe hacer cumplir esa restricción.

Creando atajos

bind() También es útil en los casos en los que desee crear un acceso directo a una función que requiera una this valor.

Llevar Array.prototype.slice(), por ejemplo, que desea utilizar para convertir un objeto similar a una matriz en una matriz real. Podrías crear un atajo como este:

const slice = Array.prototype.slice;

// ...

slice.apply(arguments);

Con bind(), esto se puede simplificar.

En el siguiente fragmento de código, slice() es una función ligada a la apply() funcion de Function, con el this valor establecido en el slice() funcion de Array.prototype. Esto significa que adicional apply() las llamadas se pueden eliminar:

//  same as "slice" in the previous example
const unboundSlice = Array.prototype.slice;
const slice = Function.prototype.apply.bind(unboundSlice);

// ...

slice(arguments);

Polyfill

Debido a que los navegadores más antiguos generalmente también son navegadores más lentos, es mucho más crítico de lo que la mayoría de la gente reconoce para crear polyfills de rendimiento para hacer que la experiencia de navegación en navegadores obsoletos sea un poco menos horrible.

Por lo tanto, a continuación se presentan dos opciones para Function.prototype.bind() polyfills:

  1. El primero es mucho más pequeño y de mayor rendimiento, pero no funciona cuando se usa el new operador.
  2. El segundo es más grande y de menor rendimiento, pero permite cierto uso del new operador en funciones vinculadas.

Generalmente, en la mayoría de los códigos es muy raro ver new se usa en una función enlazada, por lo que generalmente es mejor optar por la primera opción.

//  Does not work with `new (funcA.bind(thisArg, args))`
if (!Function.prototype.bind) (function(){
  var slice = Array.prototype.slice;
  Function.prototype.bind = function() {
    var thatFunc = this, thatArg = arguments[0];
    var args = slice.call(arguments, 1);
    if (typeof thatFunc !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - ' +
             'what is trying to be bound is not callable');
    }
    return function(){
      var funcArgs = args.concat(slice.call(arguments))
      return thatFunc.apply(thatArg, funcArgs);
    };
  };
})();

Puede solucionar parcialmente esto insertando el siguiente código al comienzo de sus scripts, lo que permite el uso de gran parte de la funcionalidad de bind() en implementaciones que no lo soportan de forma nativa.

//  Yes, it does work with `new (funcA.bind(thisArg, args))`
if (!Function.prototype.bind) (function(){
  var ArrayPrototypeSlice = Array.prototype.slice;
  Function.prototype.bind = function(otherThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var baseArgs= ArrayPrototypeSlice.call(arguments, 1),
        baseArgsLength = baseArgs.length,
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          baseArgs.length = baseArgsLength; // reset to default base arguments
          baseArgs.push.apply(baseArgs, arguments);
          return fToBind.apply(
                 fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs
          );
        };

    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
})();

Algunas de las muchas diferencias (bien puede haber otras, ya que esta lista no intenta seriamente ser exhaustiva) entre este algoritmo y el algoritmo especificado son:

  • La implementación parcial se basa en Array.prototype.slice(), Array.prototype.concat(), Function.prototype.call() y Function.prototype.apply(), métodos incorporados para tener sus valores originales.
  • La implementación parcial crea funciones que no tienen una “píldora venenosa” inmutable caller y arguments propiedades que arrojan un TypeError al obtener, configurar o eliminar. (Esto podría agregarse si la implementación admite Object.defineProperty, o implementado parcialmente [without throw-on-delete behavior] si la implementación apoya el __defineGetter__ y __defineSetter__ extensiones.)
  • La implementación parcial crea funciones que tienen un prototype propiedad. (Las funciones enlazadas adecuadas no tienen ninguna).
  • La implementación parcial crea funciones vinculadas cuyas length la propiedad no está de acuerdo con lo ordenado por ECMA-262: crea funciones con length de 0. Una implementación completa, según la longitud de la función de destino y el número de argumentos preespecificados, puede devolver una longitud distinta de cero.
  • La implementación parcial crea funciones vinculadas cuyas name La propiedad no se deriva del nombre de la función original. Según ECMA-262, el nombre de la función enlazada devuelta debe ser “enlazada” + nombre de la función de destino (observe el carácter de espacio).

Si elige utilizar esta implementación parcial, no debe confiar en aquellos casos en los que el comportamiento se desvíe de ECMA-262, 5th ¡edición! Afortunadamente, estas desviaciones de la especificación rara vez (si alguna vez) surgen en la mayoría de las situaciones de codificación. Si no comprende alguna de las desviaciones de la especificación anterior, entonces es seguro en este caso particular no preocuparse por estos detalles de desviación que no cumplen.

Si es absolutamente necesario y el rendimiento no es una preocupación., se puede encontrar una solución mucho más lenta (pero más compatible con las especificaciones) en https://github.com/Raynos/function-bind.

Especificaciones

Especificación
Especificación del lenguaje ECMAScript (ECMAScript)
# sec-function.prototype.bind

Compatibilidad del navegador

Escritorio Móvil
Cromo Borde Firefox explorador de Internet Ópera Safari WebView Android Chrome Android Firefox para Android Opera Android Safari en IOS Internet de Samsung
bind 7 12 4 9 11,6 5.1 4 18 4 12 6 1.0

Ver también

  • Function.prototype.apply()
  • Function.prototype.call()
  • Funciones