Привязать больше аргументов уже связанной функции в 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 ] );