Привязать больше аргументов уже связанной функции в Javascript

Я пытаюсь рассказать о том, как работает javascript bind().

Я вижу, что если я делаю

var f = function (a) { ... }
var g = f.bind(obj);
g(1)

то f вызывается с obj как this и 1 как a.

Я думал, что g - это функция-обертка вокруг f.

Но когда я делаю

var f = function (a) { ... }
var g = f.bind(obj);
g.call(1)

то f вызывается с 1 как this и a undefined.

Итак, кажется, что g не просто простая оболочка, но call каким-то образом отличает нормальные и связанные функции.

Еще одна вещь: я не могу частично применять функцию больше раз.

var f = function (a) { ... }
var g = f.bind(obj);
var h = g.bind(1);
h();

Тогда f вызывается с obj как this и a undefined.

В чем причина такого поведения?

Edit

Конструкции в этом вопросе на самом деле неправильны, см. принятый ответ о том, как им это нравится (в общем, я не заметил, что call и bind всегда должен иметь аргумент контекста в качестве первого аргумента).

Ответ 1

После привязки объекта к функции с помощью bind вы не можете переопределить его. Это четко написано в спецификациях, как вы можете видеть в документации MDN:

"Функция bind() создает новую функцию (связанную функцию) с тем же самым телом функции (внутреннее свойство вызова в терминах ECMAScript 5) в качестве функции, на которую она вызывается (функция целевой функции привязки), с этим значение, связанное с первым аргументом bind(), , который нельзя переопределить."

Это означает, что также:

g.call(1);

Вы получите obj как this, а не 1 - в браузерах, следующих за спецификациями.

Вы можете, конечно, связывать несколько аргументов, поэтому:

var sum = function(a, b, c) { return a + b + c };
var sumAB = sum.bind(null, 1, 5);
var sumC = sumAB.bind(null, 2);

console.log(sumC());

Но объект контекста всегда будет указан с первым bind, потому что он не может быть перезаписан.

Чтобы избежать путаницы, первый аргумент call - это объект контекста (this), тогда вы будете иметь остальную часть аргумента.

Это означает:

var obj = { foo: function(bar) { console.log(bar) } };

obj.foo('hello');

// equivalent to:
var foo = obj.foo;

foo.call(obj, 'hello');

Надеюсь, что это поможет.

Ответ 2

Вы никогда не передавали никаких аргументов - вы только установили контекст. call первый аргумент принимается как контекст (this), а аргументы 2 принимаются в качестве аргументов вызываемой функции 1 и далее. Между тем bind создает новую функцию с новым контекстом - аргументы передаются при вызове.

Ниже перечислены способы передачи 1 в качестве функции f аргумента a следующего с вашего первого блока кода:

f( 1 );
g( 1 );
g.call( this, 1 );
g.apply( this, [ 1 ] );