// Это фабричная функция, которая возвращает новый объект range,
function range(from, to) {
// Использует функцию inherit() для создания объекта, наследующего объект-прототип,
// определяемый ниже. Объект-прототип хранится как свойство данной функции
// и определяет общие методы (поведение) для всех объектов range,
var r = inherit(range.methods);
// Сохранить начальное и конечное значения в новом объекте range.
// Это не унаследованные свойства, и они являются уникальными для данного объекта,
r.from = from;
r.to = to;
// В заключение вернуть новый объект
return r;
}
// Ниже следует объект-прототип, определяющий методы, наследуемые всеми объектами range,
range.methods = {
// Возвращает true, если х - объект класса range, в противном случае возвращает false
// Этот метод может работать не только с числовыми диапазонами,
// но также с текстовыми диапазонами и с диапазонами дат Date,
includes: function(x) { return this.from <= x && x <= this.to; },
// Вызывает f для каждого целого числа в диапазоне.
// Этот метод может работать только с числовыми диапазонами,
foreach: function(f) {
for(var х = Math.ceil(this.from); x <= this.to; x++) f(x);
}
// Возвращает строковое представление диапазона
toString: function() { return "(" + this.from + "..." + this.to + ")" }
}
// Ниже приводится пример использования объекта range.
var r = range(1,3);
// Создать новый объект range
r.includes(2);
// => true: число 2 входит в диапазон
r.foreach(console.log);
// Выведет 1 2 3
console.log(r);
// Выведет (1...3)
В примере 9.1 есть несколько интересных моментов, которые следует отметить особо. Здесь определяется фабричная функция range(), которая используется для создания новых объектов range. Обратите внимание, что для хранения объекта-прототипа, определяющего класс, используется свойство range.methods функции range(). В таком способе хранения объекта-прототипа нет ничего необычного. Во-вторых, отметьте, что функция range() определяет свойства from и to для каждого объекта range. Эти не общие, не унаследованные свойства определяют уникальную информацию для каждого отдельного объекта range. Наконец, обратите внимание, что все общие, унаследованные методы, определяемые свойством range.methods, используют свойства from и to и ссылаются на них с помощью ключевого слова this, указывающего на объект, относительно которого вызываются эти методы. Такой способ использования this является фундаментальной характеристикой методов любого класса.
9.2. Классы и конструкторы
В примере 9.1 демонстрируется один из способов определения класса в языке JavaScript. Однако это не самый типичный способ, потому что он не связан с определением конструктора. Конструктор - это функция, предназначенная для инициализации вновь созданных объектов. Как описывалось в разделе 8.2.3, конструкторы вызываются с помощью ключевого слова new. Применение ключевого слова new при вызове конструктора автоматически создает новый объект, поэтому конструктору остается только инициализировать свойства этого нового объекта. Важной особенностью вызова конструктора является использование свойства prototype конструктора в качестве прототипа нового объекта. Это означает, что все объекты, созданные с помощью одного конструктора, наследуют один и тот же объект-прототип и, соответственно, являются членами одного и того же класса. В примере 9.2 демонстрируется, как можно было бы реализовать класс range, представленный в примере 9.1, не с помощью фабричной функции, а с помощью функции конструктора: