Pregunta

De: http://ejohn.org/apps/learn/#2

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

Puede alguien decirme por qué es necesaria la segunda vuelta (antes fn.apply)?

Además, ¿alguien puede explicar por qué es necesario args.concat? ¿Por qué no se puede volver a escribir como:

fn.apply(object, args)

en lugar de

return fn.apply(object,
          args.concat(Array.prototype.slice.call(arguments)));
¿Fue útil?

Solución

Es necesaria la segunda vuelta porque de lo contrario vamos a perder cualquier valor de retorno de la función de salto.

Es posible que ya lo saben, pero no se pierde nada de mención. Si no nos envolvemos fn.apply dentro de otra función, entonces estamos llamando directamente a la fn función que es sub-óptimo, como bind se supone que sólo establecer el contexto de ejecución (lo que debería hacer referencia a this dentro de la función), y no se debe invocar .

métodos de JavaScript puede ser invocada mediante una llamada al método call o apply en ellos. He aquí un pequeño ejemplo:

function example() {
    alert("useless example");
}

example.apply() // or example.call(), alerts "useless example";

La función externa en lazo de Prototipo () se supone que funciona como una envoltura invisible alrededor de la función límite. De este modo los argumentos que se pasan a la envoltura deben ser pasados ??a la función de salto así, y tiene que devolver cualquier valor que el límite devuelve la función, que es la razón por la instrucción de retorno está ahí.

La razón para hacer args.concat dentro fn.apply es diferente y no es opcional. bind en Prototipo le permite anteponer argumentos a la función límite.

args representa los argumentos que se han pasado cuando llamamos bind en la función. arguments representa los argumentos que se han pasado cuando llamamos a la función de salto. Básicamente estamos concatenando dos matrices allí.

En el ejemplo anterior:

var obj = { x: 'prop x' };
var boundExample = example.bind(obj, 12, 23); // args => 12, 23
boundExample(36, 49); // arguments => 36, 49

// arguments that our example() function receives => 12, 23, 36, 49

Otros consejos

Mensaje viejo, sino un nuevo enfoque;)

Function.prototype.bind = function(){
    var fn = this, 
    context = arguments[0], 
    args = Array.prototype.slice.call(arguments, 1);
    return function(){
        return fn.apply(context, args.concat([].slice.call(arguments)));
    }
}

obj = {'abc':'x'};
var func = function() {
  console.log(arguments);
  alert(this.abc);
}
var x = func.bind(obj);

console.log(x(1,2,3));

Este es un ejemplo muy bueno de explicar. Ejecutarlo y comprobar el registro de la consola. A continuación, modifique el código para dejar de lado

[].slice.call(arguments)

Se verá que el console.log de la ejecución de x (1,2,3) no se muestra los argumentos más. Esto es porque los objetos de los argumentos es una variable local dentro de todas las funciones. Esto puede sonar un poco confuso, pero lo que significa es básicamente:

var x = func.bind(obj,1,2,3);

Devuelve esta función internamente:

function() {
    return fn.apply(obj, [1,2,3].concat([].slice.call(arguments)));
}

Por lo tanto, es más de una plantilla para la función.

Cuando no se ejecuta ahora como:

x(4,5,6)

Esta será RAN:

fn.apply(obj, [1,2,3].concat([].slice.call(arguments)))

con argumentos especiales objeto = {0: 4,1: 5,2: 6}, que se puede convertir en una matriz utilizando [] .slice.call donde los argumentos es un objeto local, que automáticamente se beeing asignado durante la invocación de la función.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top