Можете ли вы восстановить функцию отскока, используя `bind`
bind
метод создает новую функцию, которая при вызове имеет ключевое слово this
, установленное на предоставленное значение.
var obj = {
a: 0,
b() {
console.log(this.a);
}
}
obj.b() // -> 0
var functionBound = obj.b.bind(obj)
functionBound() // -> 0
functionBound.bind(null)() // -> 0 AND I expect an error here
Ясно, что я не могу повторить попытку, функция уже отскочила. Однако я не мог найти никакой документации по этому поведению.
Цитата из "Привязать больше аргументов уже связанной функции в Javascript"
Как только вы привязали объект к функции со связыванием, вы не можете ее переопределить. Он четко написан в спецификациях, как вы можете видеть в документации MDN:
Функция bind() создает новую функцию (связанную функцию) с тем же самым телом функции (внутреннее свойство вызова в терминах ECMAScript 5) в качестве функции, на которую она вызывается (функция целевой функции привязки), с этим значением связанный с первым аргументом bind(), который нельзя переопределить.
Я не мог найти их в документации MDN. Я сделал точный полнотекстовый поиск по приведенной выше цитате в Google и кажется, что ответ SO выше - единственный источник такого поведения. Я также пытаюсь найти ответ в спецификации языка без везения.
Мой вопрос: знаете ли вы это поведение и где я могу найти официальную документацию по этим вопросам?
Ответы
Ответ 1
Это не может напрямую ответить на вопрос о получении официально задокументированной спецификации, подтверждающей это поведение, но мы можем основывать наши выводы на исходном коде, представленном в MDN, в частности, в документации для Function.prototype.bind(), в разделе Polyfill, где они приводят пример того, как a polyfill bind
будет выглядеть.
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
}
Мы можем видеть, что параметр oThis
используется в замыкании fBound
, который является окончательным результатом функции bind
.
Это означает, что при вызове функции bind
вы получаете функцию закрытия в обратном порядке, которая при вызове обращается к свободной переменной oThis
, предоставляемой как параметр в исходном вызове bind
.
Таким образом, не имеет значения, сколько раз вы повторно привязываете функцию bound fBound
, эта функция уже привязана навсегда к исходному контексту oThis
в пределах его закрытия.
Документация MDN также указывает на приложение привязки Raynos для дальнейшего использования, что также соответствует этому примеру.
Ответ 2
Проблема в том, что Function.prototype.bind возвращает новую функцию вместо нее. Вызов связанной функции с другим этим аргументом не имеет никакого эффекта, потому что связанная функция уже знает, какое значение использовать в качестве этого аргумента.
Вы можете использовать это для привязки своих функций:
Function.boundOriginProp = Symbol()
Function.prototype.bindDynamic = thisArg => {
let origin = this[Function.bindOriginProp] || this
let bound = (...args) => origin.call(thisArg, ...args)
bound[Function.bindOriginProp] = origin
return bound
}
Таким образом, вы можете восстановить функции, которые уже были связаны следующим образом:
let obj1 = { value: 1 }
let obj2 = { value: 2 }
function example() {
console.log(this.value)
}
let fn1 = example.bindDynamic(obj1)
fn1() // -> 1
let fn2 = fn1.bindDynamic(obj2)
fn2() // -> 2
let fn3 = fn1.bindDynamic(null)
fn3() // -> undefined
Я надеюсь, что это может вам помочь;)
Ответ 3
Метод привязки обертывает исходную функцию и создает новую ограниченную функцию.
Фактически, функция, которая обертывает исходную функцию, сохраняя одно и то же тело исходной функции.
Это определение на веб-сайте MDN:
Функция bind() создает новую связанную функцию (BF). BF является экзотический функциональный объект (термин из ECMAScript 2015), который обертывает оригинальный функция объект. Вызов BF обычно приводит к выполнение его завернутой функции.
Итак, каждый раз, когда вы вызываете .bind
, вы создаете новую функцию, передающую контекст как первый параметр, а args - как остальные параметры, но сохраняя тело первого определения.
Вы также можете переопределить исходный объект и снова привязать функцию.
В то же время вы можете также взять ранее ограниченную функцию и связать ее снова с новой функцией.
В следующем примере вы должны увидеть ожидаемое поведение:
var printer = function(a) {
console.log(a);
};
var printer1 = printer.bind(null, 1);
var printer2 = printer.bind(null, 2);
var printer3 = printer.bind(null, 3);
printer1();
printer2();
printer3();
printer = function(a) {
console.log("I am a new " + a);
};
var printer4 = printer.bind(null, 4);
printer4();
var newPrinter = function() {
console.log('I am a new printer!');
}
printer4 = newPrinter.bind(null);
printer4();