JavaScript. Подробное руководство, 6-е издание, стр. 123
<b> // Не сохраняет границы в свойствах объекта. Вместо этого определяет функции доступа,</b><b> // возвращающие значения границ. Сами значения хранятся в замыкании,</b><b> this.from = function() { return from; };</b><b> this.to = function() { return to; };</b><b>}</b><b>// Методы прототипа не имеют прямого доступа к границам: они должны вызывать</b><b>// методы доступа, как любые другие функции и методы.</b><b>Range.prototype = { constructor: Range,</b><b> includes: function(x) { return this.from() <= x && x <= this.to(); },</b><b> foreach: function(f) {</b><b> for(var x=Math.ceil(this.from()), max=this.to(); x <= max: x++) f(x);</b><b> },</b><b> toString: function() { return "(" + this.from() + "..." + this.to() + ")"}</b><b>};</b>Новый класс
<b>Range</b><b>Range</b><b>from</b><b>to</b><b>Range</b><b>var r = new Range(1,5): // "неизменяемый" диапазон</b><b>r.from = function() { return 0; }; // Изменчивость имитируется заменой метода</b>Имейте в виду, что такой прием инкапсуляции имеет отрицательные стороны. Класс, использующий замыкание для инкапсуляции, практически наверняка будет работать медленнее и занимать больше памяти, чем эквивалент с простыми свойствами.
9.6.7. Перегрузка конструкторов и фабричные методы
Иногда бывает необходимо реализовать возможность инициализации объектов несколькими способами. Например, можно было бы предусмотреть возможность инициализации объекта
<b>Complex</b><b>Set</b>Один из способов реализовать такую возможность заключается в создании перегруженных версий конструктора и выполнении в них различных способов инициализации в зависимости от передаваемых аргументов. Ниже приводится пример перегруженной версии конструктора
<b>Set</b><b>function Set() {</b><b> this.values = {}; // Свойство для хранения множества</b><b> this.n =0; // Количество значений в множестве</b><b> // Если конструктору передается единственный объект, подобный массиву,</b><b> // он добавляет элементы массива в множество.</b><b> // В противном случае в множество добавляются все аргументы</b><b> if (arguments.length == 1 && isArraylike(arguments[0]))</b><b> this.add.apply(this, arguments[0]);</b><b> else</b><b> if (arguments.length > 0)</b><b> this.add.apply(this, arguments);</b><b>}</b>Такое определение конструктора
<b>Set()</b><b>add()</b>В случае с комплексными числами реализовать перегруженную версию конструктора, которая инициализирует объект полярными координатами, вообще невозможно. Оба представления комплексных чисел состоят из двух вещественных чисел. Если не добавить в конструктор третий аргумент, он не сможет по своим аргументам определить, какое представление следует использовать. Однако вместо этого можно написать фабричный метод - метод класса, возвращающий экземпляр класса. Ниже приводится фабричный метод, возвращающий объект
<b>Complex</b><b>Complex.polar = function(r, theta) {</b><b> return new Complex(r*Math.cos(theta), r*Math.sin(theta));</b><b>};</b>А так можно реализовать фабричный метод для инициализации объекта
<b>Set</b><b>Set.fromArray = function(a) {</b><b> s = new Set(); // Создать пустое множество</b><b> s.add.apply(s, a); // Передать элементы массива методу add</b><b> return s; // Вернуть новое множество</b><b>};</b>Привлекательность фабричных методов заключается в том, что им можно дать любые имена, а методы с разными именами могут выполнять разные виды инициализации. Поскольку конструкторы играют роль имен классов, обычно в классах определяется единственный конструктор. Однако это не является непреложным правилом. В языке JavaScript допускается определять несколько функций-конструкторов, использующих общий объект-прототип, и в этом случае объекты, созданные разными конструкторами одного класса, будут иметь один и тот же тип. Данный прием не рекомендуется к использованию, тем не менее ниже приводится вспомогательный конструктор такого рода: