Function.prototype.bind()

Resumen

El m茅todo bind() crea una nueva funci贸n, que cuando es llamada, asigna a su operador  this el valor entregado, con una secuencia de argumentos dados precediendo a cualquiera entregados cuando la funci贸n es llamada. 

El valor de this es ignorado cuando la funci贸n es llamada con el operador new.

Sintaxis

fun.bind(thisArg[, arg1[, arg2[, ...]]])

Parametros

thisArg
Es un valor que ser谩 enviado a la funci贸n destino cuando se llame a la funci贸n de enlace. Este valor ser谩 ignorado si la funci贸n de enlace es construida usando el operador new.
arg1, arg2, ...
Son los argumentos que se enviar谩n adem谩s de los provistos a la funci贸n de enlace cuando se invoque la funci贸n destino.

Valor de retorno

Una copia de la funci贸n entregada con el valor especificado this y los argumentos iniciales.

Descripci贸n

La funci贸n bind() crea una nueva funci贸n (funci贸n ligada) con el mismo cuerpo (propiedad interna call en t茅rminos de ECMAScript 5) como la funci贸n que ser谩 llamada (la funci贸n objetivo de la funci贸n ligada) con la referencia this asociada al primer argumento de bind(), el cual no podr谩 ser sobreescrito. bind() tambi茅n acepta par谩metros predeterminados que anteceder谩n al resto de los par谩metros espec铆ficos cuando la funci贸n objetivo sea llamada. Una funci贸n ligada tambi茅n puede ser constru铆da utilizando el operador new: al hacerlo, actuar谩 como si en su lugar hubiera sido constru铆da la funci贸n objetivo.

En este 煤ltimo caso, el par谩metro correspondiente para this ser谩 ignorado, aunque los par谩metros predeterminados que anteceder谩n al resto s铆 ser谩n provistos para la funci贸n emulada.

Ejemplos

Ejemplo: Crear una funci贸n ligada

El uso m谩s simple de bind() es hacer que una funci贸n que, sin importar c贸mo es llamada, siempre apunte al mismo objeto con la referencia this. Un error com煤n para nuevos programadores de JavaScript es que obtienen una referencia a un m茅todo de un objeto, posteriormente ejecutan ese m茅todo desde la referencia externa y esperan que la referencia de this siga apuntando al objeto original de donde se obtuvo el m茅todo (v.g. cuando se usa ese m茅todo en un callback). Sin el debido cuidado, el objeto original es com煤nmente perdido. Creando una funci贸n ligada desde la funci贸n  empleando el objeto original, resuelve limpiamente este problema:

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

module.getX(); // 81

var getX = module.getX;
getX(); // 9, porque en este caso, "this" apunta al objeto global

// Crear una nueva funci贸n con 'this' asociado al objeto original 'module'
var boundGetX = getX.bind(module);
boundGetX(); // 81

Ejemplo: Funciones Parciales

El siguiente uso simple de bind() es definir una funci贸n con argumentos predeterminados que preceder谩n a los argumentos finales de la funci贸n ligada. Estos argumentos iniciales (en caso de haberlos) se definen a continuaci贸n de lo que ser谩 la referencia de this y son entonces enviados como argumentos de la funci贸n objetivo, seguidos por los argumentos enviados a la funci贸n ligada cada vez que dicha funci贸n sea llamada.

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

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

// Crear funcion (sin referencia this) con argumento inicial predeterminado
var leadingThirtysevenList = list.bind(undefined, 37);

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

Ejemplo: Con setTimeout

De manera predeterminada, dentro de window.setTimeout(), la palabra reservada this ser谩 setteada al objeto window (o a global). Cuando se est茅 trabajando con m茅todos de clase que requieran que this se refiera a instancias de clase, usted puede expl铆citamente ligar this a la funci贸n callback para mantener la referencia de la instancia.

function LateBloomer() {
  this.petalCount = Math.ceil(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!');
};

Ejemplo: Funciones ligadas usadas como constructores

Advetencia: Esta secci贸n demuestra las capacidades de JavaScript y documenta algunos usos extremos del m茅todo bind(). Los m茅todos mostrados a continuaci贸n no son la mejor forma de hacer las cosas y probablemente no deber铆an ser utilizados en ning煤n ambiente productivo.

Las funciones ligadas son autom谩ticamente adecuadas para usarse con el operador new para construir nuevas instancias creadas por la funci贸n objetivo. Cuando una funci贸n ligada es utilizada para construir un valor, el par谩metro enviado para reemplazar la referencia this es ignorado. De cualquier forma, los argumentos iniciales s铆 son tomados en consideraci贸n y anteceder谩n a los par谩metros que se env铆en al constructor:

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

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

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


var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// not supported in the polyfill below,
// works fine with native bind:
var YAxisPoint = Point.bind(null, 0/*x*/);

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

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

Note que no necesita hacer nada especial para crear una funci贸n ligada para usarse con new. El razonamiento es que usted no necesita hacer nada especial para crear una funci贸n ligada para ser llamada planamente, a煤n si usted prefiriera requerir que la funci贸n ligada sea llamada 煤nicamente utilizando new.

// Ejemplo que puede ser ejecutado directamente en tu consola JavaScript
// ...contin煤a de arriba

// A煤n puede ser invocada como una funci贸n normal
// (aunque es usualmente indeseable)
YAxisPoint(13);

emptyObj.x + ',' + emptyObj.y;
// >  '0,13'

Si desea utilizar una funci贸n ligada 煤nicamente usando new, o 煤nicamente mediante una llamada directa, la funci贸n objetivo debe forzar esa restricci贸n.

Ejemplo: Crear atajos

bind() tambi茅n es 煤til en casos en los que desea crear un atajo para una funci贸n que requiere una referencia espec铆fica para this.

Tomando Array.prototype.slice, por ejemplo, el cual se desear铆a utilizar para convertir un objeto tipo array a un arreglo real. Podr铆a crear un atajo como el siguiente:

var slice = Array.prototype.slice;

// ...

slice.call(arguments);

Con bind(), esto puede ser simplificado. En el siguiente fragmento de c贸digo, slice es una funci贸n ligada a la funci贸n call() de Function.prototype, con la referencia this setteada a la funci贸n slice() de Array.prototype. Esto significa que llamadas adicionales a call() pueden omitirse:

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

// ...

slice(arguments);

Polyfill

La funci贸n bind() fue a帽adida a la especificaci贸n ECMA-262, 5a edici贸n; por lo tanto podr铆a no estar presente en todos los navegadores. Usted puede parcialmente simularla al insertar el siguiente c贸digo al inicio de sus scripts, permitiendo emplear muchas de las funcionalidades de bind() en implementaciones que no la soportan nativamente.

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    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 aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP && oThis
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
  };
}

Algunas de las muchas diferencias (bien podr铆a haber otras, en tanto la siguiente lista no intenta ser exhaustiva) entre este algoritmo y el algoritmo de la especificaci贸n 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 "poison pills" inmutables caller y las propiedades de los argumentos que lanzan una TypeError sobre get, set, o deletion. (Esto podr铆a ser a帽adido si la implementaci贸n soportara Object.defineProperty, o parcialmente implementada [sin el comportamiento throw-on-delete] si la implementaci贸n soportara las extensiones __defineGetter__ y __defineSetter__ ).
  • La implementaci贸n parcial crea funciones que tienen una propiedad prototype. (Las funciones ligadas no tienen ninguna).
  • La implementaci贸n parcial crea funciones ligadas cuya propiedad length no coincide con la indicada por ECMA-262: 茅sta crea funciones con longitud 0, mientras que la implementaci贸n completa, dependiendo de la longitud de la funci贸n objetivo y del n煤mero de argumentos pre-especificados, podr铆a regresar una longitud mayor a zero.

Si elige usar esta implementaci贸n parcial, no debe de utilizarla en los casos en los que el comportamiento es distinto al de la especificaci贸n ECMA-262, 5th edition! Con un poco de cuidado, de cualquier manera (y tal vez con algunas modificaciones adicionales para adecuarse a sus necesidades espec铆ficas), esta implementaci贸n parcial podr铆a ser un puente razonable al momento en que bind() sea ampliamente implementada acorde a a la especificaci贸n.

Por favor checa https://github.com/Raynos/function-bind para ver una soluci贸n m谩s profunda.

Especificaciones

Compatibilidad de navegadores

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!
Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 7 4.0 (2) 9 11.60 5.1.4
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support 4.0 0.16 4.0 (2) ? 11.50 6.0

Basado en Kangax's compat tables.

Ver tambi茅n