2012-08-01 18 views
11

Soy un gran admirador de ES5 Function.prototype.bind y argumentos currying (básicamente creando argumentos predeterminados para funciones).Confusión sobre Function.prototype.bind()

Estaba bromeando con eso un poco, pero ya no puedo imaginar mi propia construcción. Esta es mi campo de juego:

function hello(arg1, arg2) { 
    console.log('hello()'); 
    console.log('"this" is: ', this); 
    console.log('arguments: ', arguments); 
} 

var foo = Function.prototype.call.bind(hello,{what: 'dafuq'}, 2); 
foo(42); 

La salida del registro para esto es la siguiente:

hello() 
"this" is: Object{ what="dafuq" } 
arguments: [2,42] 

Pero no entiendo cómo en la tierra el objeto {what: 'dafuq'} se abre paso como una referencia para la this dentro foo. Por lo que yo entiendo, estamos creando una llamada enlazada a Function.prototype.call. Vamos a comprobar la sinopsis MDN para .bind() rápidamente:

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

así, thisArg para .call es la función hello, seguido de la lista de argumentos. Básicamente lo que sucede es esto

Function.prototype.call.call(hello, {what: 'dafuq'}, 2); 

... uuhhh ahora me duele un poco el cerebro. Creo que ahora tengo una idea de lo que sucede, pero que alguien encuentre buenas palabras sólidas para explicarlo en detalle.

  • cómo {what: 'dafuq'} se convierte en el this reference

Respuesta

6

Pero no entiendo cómo en la tierra el objeto {what: 'dafuq'} se abre paso como una referencia para el presente dentro de foo

Es porque foo es efectivamente el método call con la función hello enlazada como contexto de llamada, y ese objeto enlazado como primer argumento. El primer argumento de .callestablece el contexto de llamada de su contexto de llamada. Como lo ha vinculado, significa que el objeto siempre será el contexto de llamada.


ponerlo de esta manera ...

Usted ha obligado el contexto llamar de .call-hello.

Esto es efectivamente lo mismo que hacer ...

hello.call(); 
// or... 
// Function.prototype.call.call(hello); 

Usted también ha obligado al primer argumento de .call-{what: "dafuq"}, así que esto es efectivamente lo mismo que hacer ...

hello.call({what: "dafuq"}); 
// or... 
// Function.prototype.call.call(hello, {what: "dafuq"}); 

Y, por último, que ha obligado el segundo argumento de .call-2, así que esto es efectivamente lo mismo que hacer ...

hello.call({what: "dafuq"}, 2); 
// or... 
// Function.prototype.call.call(hello, {what: "dafuq"}, 2); 
+0

sí 'foo' es el método de llamada, pero nunca llamamos' foo.call (thisArg) '¿verdad? simplemente lo llamamos directamente por '()'. No lo entiendo: p – jAndy

+0

@jAndy: Vincula el primer argumento de '.call' usando' .bind' a su objeto. Entonces, dado que esta "versión" de '.call' tiene un primer argumento vinculado, siempre lo usará como contexto de llamada. –

+0

la "versión" vinculada de '.call()' debería tener 'hello' como thisArg, ¿no? Después de eso, ejecutamos ese límite '.call()' solo pasando en parámetros formales. Doh, bien podría ser. Estoy mentalmente bloqueado aquí, todavía lo estoy imaginando. – jAndy

8

No está llamando .bind(thisArg, args), pero
Function.prototype.bind.call(thisArgUsedByCall, thisArgUsedByBind, argument).

Una forma diferente de mostrar lo que sucede:

// thisArgUsedByCall is a function 
Function.prototype.call(thisArgUsedByCall, ...) // does the same as: 
thisArgUsedByCall.bind(thisArgUsedByBind, argument); 
+0

bien, eso hace que sea más evidente. Buena respuesta. – jAndy

2

La respuesta corta es que se unen consume el primer argumento y lo usa como este, pero luego la llamada consume su primer argumento (que era el segundo argumento de bind).

de enlace funciona así:

fun.bind(thisArg, argArgs...)(x, y, ...) 

convierte

fun(argArgs..., x, y, ....) // this = thisArg 

Así

foo(42) 

es

Function.prototype.call.bind(hello, { what: 'dafuq' }, 2) (42) 

que se convierte en

Function.prototype.call({ what: 'dafuq' }, 2, 42) // this = hello 

de llamadas funciona así:

fun.call(thisArg, argArgs) 

Se convierte en

fun(argArgs) // this = thisArg 

por lo

call({ what: 'dafuq' }, 2, 42) // this = hello 

convierte

hello(2, 42) // this = { what: 'dafuq' } 
+0

* "(No sé de dónde viene ese 5)" * - ¿Qué cinco? –

+0

Parece que se arregló, era un error tipográfico en la publicación principal. Editado mi respuesta a cambio. – royh