Подтвердить что ты не робот

Функция F() {if (! (этот экземпляр F)) {return new F()};...}

Каково использование конструкции: function F() { if (!(this instanceof F)) { return new F() }; ... }?

Я нашел это в pty.js для Node. Вот исходный код:

function Terminal(file, args, opt) {
  if (!(this instanceof Terminal)) {
     return new Terminal(file, args, opt);
  }

  var self = this
     , env
     , cwd
     , name
     , cols
     , rows
     , term;
-------------------SKIP-----------------------------------
  Terminal.total++;
  this.socket.on('close', function() {
     Terminal.total--;
     self._close();
     self.emit('exit', null);
  });

  env = null;
}
4b9b3361

Ответ 1

Это означает, что если функция была вызвана без оператора new, она автоматически вернет новый экземпляр.

Например, если у вас не было этой защиты и сделал это...

var t = Terminal();

... тогда this при выполнении Terminal() будет указывать на window (или ваш глобальный объект, причудливый не-браузерный парень/галлон), определенно не то, что вы хотите.

Определив, что this на самом деле является экземпляром Terminal, мы можем продолжить. В противном случае защита возвращает новый объект.

Тогда мы можем просто использовать обе формы...

var t = Terminal(); // Will be same as `new Terminal()`

Ответ 2

Это просто, чтобы убедиться, что он будет работать, даже если F вызывается без new.

Когда вы вызываете F с new, в этой функции this находится новый экземпляр.

Затем, если this не является экземпляром F (!(this instanceof F)), это означает, что F не вызывается с помощью new. В этом случае F вызывает себя, теперь с new.

Ответ 3

В дополнение к великим объяснениям в этой теме интересно посмотреть, что происходит под капотом. Спецификация ECMAScript (где основан Javascript) определяет глобальный объект. Это выполняется по-разному в разных средах исполнения. В вашем типичном браузере это объект window, а в Node.js - это объект root. Каждая функция, определенная "в дикой природе" (не привязанная к создаваемому пользователем объекту), станет свойством глобального объекта. В Node.js вы можете попробовать:

> function Test() {};
> root.Test
[Function: Test]

Теперь переменная this указывает на объект, членом которого является функция. Итак, в приведенном выше примере:

> function Test() { 
... console.log(this === root); 
... };
> Test()
true

То же самое касается вашей функции Terminal. Если вы запустите его, this укажет на глобальный объект, который, конечно, не экземпляр Terminal!

При вызове функции с помощью оператора new возвращается объект, который будет иметь доступ к свойству с именем constructor, которое будет ссылаться на эту функцию. Это нечто эквивалентное:

> var instance = {};
> instance.constructor = Terminal;
> instance.constructor();

Итак, когда условие терпит неудачу, и функция терминала запускается через строку new Terminal(), this указывает на вновь созданный экземпляр, который типа Terminal!

Если вы хотите получить больше технических данных, instance не имеет свойства constructor. Он привязан (через цепочку прототипов *) к частному объекту ** (созданному во время выполнения), который имеет свойство constructor, указывающее на функцию терминала. Этот частный объект привязан к функцией через свойство prototype. D.Crockford представляет это в псевдокоде следующим образом:

Terminal.prototype = {constructor: Terminal};

Опять же, это только, когда вы вызываете функцию с помощью new.

* Если свойство не найдено, объект будет искать его в объекте, на который указывает свойство __proto__.

** (представьте себе что-то вроде объекта с именем _Terminal, к которому вы не можете получить доступ по имени)