Чтение онлайн

ЖАНРЫ

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

}

// Методы прототипа не имеют прямого доступа к границам: они должны вызывать

// методы доступа, как любые другие функции и методы.

Range.prototype = { constructor: Range,

includes: function(x) { return this.from <= x && x <= this.to; },

foreach: function(f) {

for(var x=Math.ceil(this.from), max=this.to; x <= max: x++) f(x);

},

toString: function { return "(" + this.from + "..." + this.to + ")"}

};

Новый

класс
Range
определяет методы для чтения значений границ диапазона, но в нем отсутствуют методы или свойства для изменения этих значений. Это обстоятельство делает экземпляры этого класса неизменяемыми: при правильном использовании границы объекта
Range
не должны изменяться после его создания. Однако если не использовать возможности ECMAScript 5 (раздел 9.8.3), свойства
from
и
to
по-прежнему остаются доступными для записи и в действительности объекты
Range
не являются неизменяемыми:

var r = new Range(1,5): // "неизменяемый" диапазон

r.from = function { return 0; }; // Изменчивость имитируется заменой метода

Имейте в виду, что такой прием инкапсуляции имеет отрицательные стороны. Класс, использующий замыкание для инкапсуляции, практически наверняка будет работать медленнее и занимать больше памяти, чем эквивалент с простыми свойствами.

9.6.7. Перегрузка конструкторов и фабричные методы

Иногда бывает необходимо реализовать возможность инициализации объектов несколькими способами. Например, можно было бы предусмотреть возможность инициализации объекта

Complex
значениями радиуса и угла (полярные координаты) вместо вещественной и мнимой составляющих. Или создавать объекты множеств
Set
, членами которых являются элементы массива, а не аргументы конструктора.

Один из способов реализовать такую возможность заключается в создании перегруженных версий конструктора и выполнении в них различных способов инициализации в зависимости от передаваемых аргументов. Ниже приводится пример перегруженной версии конструктора

Set
:

function Set {

this.values = {}; // Свойство для хранения множества

this.n =0; // Количество значений в множестве

// Если конструктору передается единственный объект, подобный массиву,

// он добавляет элементы массива в множество.

// В противном случае в множество добавляются все аргументы

if (arguments.length == 1 && isArraylike(arguments[0]))

this.add.apply(this, arguments[0]);

else

if (arguments.length > 0)

this.add.apply(this, arguments);

}

Такое

определение конструктора
Set
позволяет явно перечислять элементы множества в вызове конструктора или передавать ему массив элементов множества. К сожалению, этот конструктор имеет одну неоднозначность: его нельзя использовать для создания множества, содержащего единственный элемент-массив. (Для этого потребуется создать пустое множество, а затем явно вызвать метод
add
.)

В случае с комплексными числами реализовать перегруженную версию конструктора, которая инициализирует объект полярными координатами, вообще невозможно. Оба представления комплексных чисел состоят из двух вещественных чисел. Если не добавить в конструктор третий аргумент, он не сможет по своим аргументам определить, какое представление следует использовать. Однако вместо этого можно написать фабричный метод - метод класса, возвращающий экземпляр класса. Ниже приводится фабричный метод, возвращающий объект

Complex
, инициализированный полярными координатами:

Complex.polar = function(r, theta) {

return new Complex(r*Math.cos(theta), r*Math.sin(theta));

};

А так можно реализовать фабричный метод для инициализации объекта

Set
массивом:

Set.fromArray = function(a) {

s = new Set; // Создать пустое множество

s.add.apply(s, a); // Передать элементы массива методу add

return s; // Вернуть новое множество

};

Привлекательность фабричных методов заключается в том, что им можно дать любые имена, а методы с разными именами могут выполнять разные виды инициализации. Поскольку конструкторы играют роль имен классов, обычно в классах определяется единственный конструктор. Однако это не является непреложным правилом. В языке JavaScript допускается определять несколько функций-конструкторов, использующих общий объект-прототип, и в этом случае объекты, созданные разными конструкторами одного класса, будут иметь один и тот же тип. Данный прием не рекомендуется к использованию, тем не менее ниже приводится вспомогательный конструктор такого рода:

// Вспомогательный конструктор для класса Set.

function SetFromArray(a) {

// Инициализировать новый объект вызовом конструктора Set как функции,

// передав ей элементы массива в виде отдельных аргументов.

Set.apply(this, а);

}

// Установить прототип, чтобы функция SetFromArray создавала экземпляры Set

Поделиться с друзьями: