Задача функции mozilla bind

Возник вопрос о реализации функции связывания, которую я нашел на сайте Mozilla. По большей части это имеет смысл для меня, но я не могу понять, для чего эта проверка...

this instanceof nop ? this : ( obj || {} ) 

в функции связывания. Очевидно, что его проверка, если 'this' является пустой функцией, но зачем вам нужно связывать пустую функцию. Я попробовал его в firebug, он работает, но в чем смысл? Просто пытаюсь увеличить свои знания javascript, чтобы любая помощь была оценена.

if ( !Function.prototype.bind ) {

  Function.prototype.bind = function( obj ) {

    var slice = [].slice,
    args = slice.call(arguments, 1), 
    self = this, 
    nop = function () {}, 
    bound = function () {
      return self.apply( this instanceof nop ? this : ( obj || {} ), 
                          args.concat( slice.call(arguments) ) );    
    };

    nop.prototype = self.prototype;

    bound.prototype = new nop();

    return bound;
  };
}

Ответы

Ответ 1

Его позволяет вызывать связанную функцию как конструктор без привязки к исходному объекту. Другими словами, функция "bound" будет работать так же, как и исходная, несвязанная версия, если вы вызываете ее с помощью 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). Основное отличие состоит в том, что он игнорирует параметр "bound this", когда он вызывается как конструктор (так как внутри конструктора this должен быть вновь созданный объект). Таким образом, функция bound должна определить способ ее вызова. Например, bound(123) vs. new bound(123) и установите this соответственно.

То, в которое входит функция nop. Она по существу действует как промежуточный "класс", так что bound extends 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();), которая может иметь побочные эффекты.

Ответ 2

Я думаю, что это короткая нотация для (typeof obj != "undefined") ? obj : {}

То есть, если obj не undefined, верните obj, else, верните пустой объект ({} - пустой объект).