Путаница в функции 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' }