Книга: JavaScript. Подробное руководство, 6-е издание

9.2.2. Свойство constructor

9.2.2. Свойство constructor

В примере 9.2 свойству Range.prototype присваивался новый объект, содержащий методы класса. Хотя было удобно определить методы как свойства единственного объекта-литерала, но при этом совершенно не было необходимости создавать новый объект. Роль конструктора в языке JavaScript может играть любая функция, поскольку выражению вызова конструктора необходимо лишь свойство рrototype. Следовательно, любая функция (кроме функций, возвращаемых методом Function.bind() в ECMAScript 5) автоматически получает свойство prototype. Значением этого свойства является объект, который имеет единственное неперечислимое свойство constructor. Значением свойства constructor является объект функции:

var F = function() {}; // Это объект функции.
var р = F.prototype;   // Это объект-прототип, связанный с ней.
var c = p.constructor; // Это функция, связанная с прототипом.
c === F    // => true: F.prototype.constructor === F для всех функций

Наличие предопределенного объекта-прототипа со свойством constructor означает, что объекты обычно наследуют свойство constructor, которое ссылается на их конструкторы. Поскольку конструкторы играют роль идентификаторов классов, свойство constructor определяет класс объекта:

var о = new F(); // Создать объект класса F
о.constructor === F // => true: свойство constructor определяет класс

Эти взаимосвязи между функцией-конструктором, ее прототипом, обратной ссылкой из прототипа на конструктор и экземплярами, созданными с помощью конструктора, иллюстрируются на рис. 9.1.


Обратите внимание, что в качестве примера для рис. 9.1 был взят наш конструктор Range(). Однако в действительности класс Range, определенный в примере 9.2, замещает предопределенный объект Range.prototype своим собственным. А новый объект-прототип не имеет свойства constructor. По этой причине экземпляры класса Range, как следует из определения, не имеют свойства constructor. Решить эту проблему можно, явно добавив конструктор в прототип:

Range.prototype = {
  constructor: Range, // Явно установить обратную ссылку на конструктор
  includes: function(x) { return this.from <= x && x <= this.to; },
  foreach: function(f) {
    for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
  },
  toString: function() { return "(" + this.from + “..." + this.to + }
};

Другой типичный способ заключается в том, чтобы использовать предопределенный объект-прототип, который уже имеет свойство constructor, и добавлять методы в него:

// Здесь расширяется предопределенный объект Range.prototype,
// поэтому не требуется переопределять значение автоматически
// создаваемого свойства Range.prototype.constructor.
Range.prototype.includes = function(x) { return this.from<=x && x<=this.to; };
Range.prototype.foreach = function(f) {
  for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
};
Range.prototype.toString = function() {
  return "(" + this, from + "..." + this, to + ")";
};

Оглавление книги


Генерация: 1.084. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз