Путаница в функции Function.prototype.bind()
Я большой поклонник ES5 Function.prototype.bind
и аргументов каррирования (в основном создавая аргументы по умолчанию для функций).
Я обманывал это немного, но я не могу, чтобы жизнь меня больше определяла мою собственную конструкцию. Это моя детская площадка:
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 );
Выход журнала для этого выглядит следующим образом:
hello()
"this" is: Object{ what="dafuq" }
arguments: [2,42]
Но я не понимаю, как на земле объект {what: 'dafuq'}
делает свой путь в качестве ссылки для this
внутри foo
. Насколько я понимаю, мы создаем связанный вызов Function.prototype.call
. Позволяет быстро проверить краткое описание MDN для .bind()
:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
поэтому thisArg
для .call
- это функция hello
, за которой следует список аргументов. В основном, что происходит, это
Function.prototype.call.call( hello, {what: 'dafuq'}, 2);
... уухх, теперь мой мозг немного болит. Я думаю, что теперь у меня есть идея, что происходит, но, пожалуйста, кто-то найдет хорошие слова, чтобы объяснить это подробно.
- , как
{what: 'dafuq'}
становится this reference
Ответы
Ответ 1
Но я не понимаю, как на земле объект {what: 'dafuq'}
делает свой путь в качестве ссылки для этого внутри foo
Это потому, что foo
является эффективным способом call
с функцией hello
, связанной как вызывающий контекст, и этот объект связан как первый аргумент. Первый аргумент .call
устанавливает вызывающий контекст его вызывающего контекста. Поскольку вы связали его, это означает, что объект всегда является вызывающим контекстом.
Положите это так...
Вы связали вызывающий контекст .call
с hello
.
Это фактически то же самое, что и делать...
hello.call();
// or...
// Function.prototype.call.call(hello);
Вы также связали первый аргумент .call
с {what: "dafuq"}
, так что это фактически то же самое, что и делать...
hello.call({what: "dafuq"});
// or...
// Function.prototype.call.call(hello, {what: "dafuq"});
И, наконец, вы привязали второй аргумент .call
к 2
, так что это фактически то же самое, что и делать...
hello.call({what: "dafuq"}, 2);
// or...
// Function.prototype.call.call(hello, {what: "dafuq"}, 2);
Ответ 2
Вы не вызываете .bind(thisArg, args)
, но
Function.prototype.bind.call(thisArgUsedByCall, thisArgUsedByBind, argument)
.
Другой способ показать, что происходит:
// thisArgUsedByCall is a function
Function.prototype.call(thisArgUsedByCall, ...) // does the same as:
thisArgUsedByCall.bind(thisArgUsedByBind, argument);
Ответ 3
Короткий ответ заключается в том, что bind использует первый аргумент и использует его как это, но затем вызов потребляет свой первый аргумент (который был вторым аргументом привязки).
Привязка работает следующим образом:
fun.bind(thisArg, argArgs...)(x, y, ...)
становится
fun(argArgs..., x, y, ....) // this = thisArg
Итак,
foo( 42 )
является
Function.prototype.call.bind( hello, { what: 'dafuq' }, 2 ) ( 42 )
который становится
Function.prototype.call({ what: 'dafuq' }, 2, 42) // this = hello
Вызов работает следующим образом:
fun.call(thisArg, argArgs)
становится
fun(argArgs) // this = thisArg
так
call({ what: 'dafuq' }, 2, 42) // this = hello
становится
hello(2, 42) // this = { what: 'dafuq' }