Как оператор `new` может переопределить жесткую привязку, в Function.prototype.bind(..)

Это чисто теоретический вопрос, не относящийся ни к одному суточному проекту. Я выхожу из javascript из "вы не знаете js", и я застрял на реализации функции bind в JS. рассмотрите следующий код:

function foo(something) {
  this.a = something;
}

var obj1 = {};

var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); // 2

var baz = new bar(3);
console.log(obj1.a); // 2
console.log(baz.a); // 3

Ответы

Ответ 1

Во-первых, важно понять разницу между прототипом объекта (представленным как [[Prototype]] и доступным через функцию Object.getPrototypeOf или устаревшее свойство __proto__) и свойство для функции, имя которой prototype. Каждая функция имеет свойство с именем prototype, которое используется, когда функция вызывается с помощью new.

Когда вы вызываете функцию с new, эта функция снабжается значением this, установленным для вновь построенного объекта, прототип которого (т.е. [[Prototype]]) установлен в свойство prototype функции называемый. То есть, когда вы вызываете new Foo(), тогда, когда выполняется код внутри Foo, значение this будет объектом формы

{ [[Prototype]]: Foo.prototype }

Вкратце встретим листинг переменных:

  • fToBind - связанная функция: для foo.bind(...), Foo есть fToBind.
  • fBound является связанной версией fToBind; это возвращаемое значение операции bind. fBound действует как гейткипер для исходной функции fToBind и решает, что получает this value fToBind при его вызове.
  • oThis - это первый аргумент, переданный в bind, т.е. объект привязан к функции this.
  • fNOP - это функция, для свойства prototype установлено значение fToBind.prototype
  • fBound.prototype = new fNOP() заставляет это быть правдой:

    Object.getPrototypeOf(fBound.prototype) === fNOP.prototype
    Object.getPrototypeOf(fBound.prototype) === fToBind.prototype
    

Когда fBound вызывается с new, то this, который поставляется в fBound, имеет вид

{ [[Prototype]]: fBound.prototype }

и fBound.prototype является объектом вида

{ [[Prototype]]: fNOP.prototype }

делая полную форму this эквивалентной

{ [[Prototype]]: { [[Prototype]]: fNOP.prototype } }

Итак, fNOP.prototype находится в цепочке прототипов вновь созданного объекта this, когда fBound вызывается с new. Это то, что тестирует операция object instanceof constructor для:

Оператор instanceof проверяет наличие constructor.prototype в цепочке прототипов object.

Порядок операций между && и тройным здесь:

(this instanceof fNOP && oThis) ? this : oThis

Если this имеет fNOP.prototype в своей цепочке прототипов, а исходный вызов bind был предоставлен правдивый первый аргумент для привязки к функции, тогда используйте созданный natrually this, указанный в fBound, когда он вызывается с помощью new и передает это значение fToBind вместо привязки this.

Ответ 2

new имеет приоритет над значением границы this, потому что это означает, что язык определен.

Сначала у вас есть функция. Затем вы привязываете значение this и вызываете его нормально. Как и ожидалось, значение this является связанным значением.

Затем вы вызываете ту же функцию с new, и ваше значение переопределяется. Зачем? Поскольку вызовы, использующие new, инструктируются дизайном языка и, следовательно, реализацией языка, игнорируют значение bound this и заменяют его новым построенным объектом.

Языковая реализация - это просто программа. И, как и любая другая программа, она соответствует правилам. Таким образом, правило в этом случае заключается в том, что new получает значение this, независимо от какого-либо связанного значения.

Ответ 3

Я думаю, вы просто спрашиваете о том, как они получили работу polyfill.

В том, что polyfill, fNOP - это функция no-op (ничего не делает при вызове), которая используется просто для того, чтобы ее .prototype вставлена ​​в цепочку прототипов возвращаемой функции fBound. Это сделано здесь:

fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();

Итак, когда вызывается функция fBound (возвращающая вызывающий объект .bind()), оператор instanceof может проверить значение this внутри функции fBound, чтобы увидеть, value является экземпляром fNOP. И если это так, то это означает, что использовался new.

Это работает (вроде), потому что instanceof будет начинаться с объекта, который он дал с левой стороны, и искать цепочку прототипов, чтобы увидеть, является ли какой-либо из них тем же объектом, что и объект .prototype функции с правой стороны. Поэтому, если вызывается new, значение this будет новым объектом с fNOP.prototype в цепочке прототипов из-за установки, которая была выполнена, как показано выше.

Однако это не идеальный способ тестирования. Например, метод .call() можно было бы использовать для установки значения this для вызова другого экземпляра функции fBound. Таким образом, будет выглядеть как new, даже если это не так, и связанное значение для this не будет использоваться как значение this для вызова исходной функции.