Это позволяет вам вызывать связанную функцию как конструктор, не привязываясь к исходному объекту.Другими словами, «связанная» функция будет по-прежнему работать так же, как и исходная несвязанная версия, если вы вызовете ее с помощью new
.
Вот пример:
var obj = {};
function foo(x) {
this.answer = x;
}
var bar = foo.bind(obj); // "always" use obj for "this"
bar(42);
console.log(obj.answer); // 42
var other = new bar(1); // Call bar as a constructor
console.log(obj.answer); // Still 42
console.log(other.answer); // 1
Как это работает
Чтобы упростить объяснение, вот упрощенная версия кода, которая связывает только this
и не обрабатывает аргументы или отсутствует параметр obj:
Function.prototype.bind = function( obj ) {
var self = this,
nop = function () {},
bound = function () {
return self.apply( this instanceof nop ? this : obj, arguments );
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
Функция, которая возвращаетсяFunction.prototype.bind
ведет себя по-разному в зависимости от того, используете ли вы его как функцию или конструктор (см. Раздел 15.3.4.5.1 и 15.3.4.5.2 Спецификации языка ECMAScript 5).Основное отличие состоит в том, что он игнорирует параметр «связанный с этим», когда он вызывается как конструктор (поскольку внутри конструктора this
должен быть вновь созданным объектом).Поэтому функции bound
нужен способ определить, как она вызывается.Например, bound(123)
против new bound(123)
и установите this
соответственно.
Вот тут и появляется функция nop
. По сути, она действует как промежуточный "класс", так что bound
расширяется nop
который расширяет self
(то есть была вызвана функция bind()
).Эта часть настроена здесь:
nop.prototype = self.prototype;
bound.prototype = new nop();
Когда вы вызываете связанную функцию, она возвращает это выражение:
self.apply( this instanceof nop ? this : obj, arguments ) )
this instanceof nop
работает, следуя цепочке прототипов, чтобы определить, еслилюбой прототип this
равен nop.prototype
.При установке nop.prototype = self.prototype
и bound.prototype = new nop()
любой объект, созданный с помощью new bound()
, будет создан с исходным прототипом от self
до bound.prototype
.Поэтому внутри вызова функции this instanceof nop
(то есть Object.getPrototypeOf (nop) == nop.prototype) имеет значение true
, и self
вызывается с this
(вновь созданный объект).
При обычном вызове функции 'bound ()' (без new
) this instanceof nop
будет ложным, поэтому obj
передается как контекст this
, что вы и ожидаете от связанной функции.
Причина использования промежуточной функции состоит в том, чтобы избежать вызова исходной функции (в строке bound.prototype = new nop();
), что может иметь побочные эффекты.