Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание
- Название:JavaScript. Подробное руководство, 6-е издание
- Автор:
- Жанр:
- Издательство:Символ-Плюс
- Год:2012
- Город:СПб
- ISBN:978-5-93286-215-5
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание краткое содержание
Эта книга - одновременно и руководство программиста, и полноценный справочник по базовому языку JavaScript и клиентским прикладным интерфейсам, предоставляемым веб-броузерами.
JavaScript. Подробное руководство, 6-е издание - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Пример 9.9. Обобщенные методы, пригодные для заимствования
var generic = {
// Возвращает строку, включающую имя функции-конструктора, если доступно,
// и имена и значения всех неунаследованных свойств, не являющихся функциями.
toString: function() {
var s = '[';
// Если объект имеет конструктор и конструктор имеет имя, использовать
// это имя класса как часть возвращаемой строки. Обратите внимание, что
// свойство name функций является нестандартным и не поддерживается повсеместно,
if (this.constructor && this.constructor.name) s += this.constructor.name + ";
// Теперь обойти все неунаследованные свойства, не являющиеся функциями
var n = 0;
for(var name in this) {
if (!this.hasOwnProperty(name)) continue; // пропустить унаслед.
var value = this[name];
if (typeof value === ’function") continue; // пропустить методы
if (n++) s += ", ";
s += name + '=' + value;
}
return s + ']';
},
// Проверить равенство, сравнив конструкторы и свойства экземпляров объектов this
// и that. Работает только с классами, свойства экземпляров которых являются
// простыми значениями и могут сравниваться с помощью оператора ===.
// Игнорировать специальное свойство, добавляемое классом Set.
equals: function(that) {
if (that == null) return false;
if (this.constructor !== that.constructor) return false;
for(var name in this) {
if (name === "|**objectid**|") continue; // пропустить спец. св.
if (!this.hasOwnProperty(name)) continue; // пропустить унасл. св.
if (this[name] !== that[name]) return false; // сравнить значения
}
return true; // Объекты равны, если все свойства равны.
}
};
9.6.6. Частные члены
В классическом объектно-ориентированном программировании зачастую целью инкапсуляции, или сокрытия данных объектов внутри объектов, является обеспечение доступа к этим данным только через методы объекта и запрет прямого доступа к важным данным. Для достижения этой цели в таких языках, как Java, поддерживается возможность объявления «частных» ( private
) полей экземпляров класса, доступных только через методы экземпляров класса и невидимые за пределами класса.
Реализовать частные поля экземпляра можно с помощью переменных (или аргументов), хранящихся в замыкании, образуемом вызовом конструктора, который создает экземпляр. Для этого внутри конструктора объявляются функции (благодаря чему она получает доступ к аргументам и локальным переменным конструктора), которые присваиваются свойствам вновь созданного объекта. Этот прием демонстрируется в примере 9.10, где он используется для создания инкапсулированной версии класса Range
. Вместо простых свойств from
и to
, определяющих границы диапазона, экземпляры этой новой версии класса предоставляют методы from
и to
, возвращающие значения границ. Методы from()
и to()
не наследуются от прототипа, а определяются отдельно для каждого объекта Range
. Остальные методы класса Range
определяются в прототипе как обычно, но изменены так, чтобы вместо чтения значений границ напрямую из свойств они вызывали бы методы from()
и to().
Пример 9.10. Класс Range со слабо инкапсулированными границами
function Range(from, to) {
// Не сохраняет границы в свойствах объекта. Вместо этого определяет функции доступа,
// возвращающие значения границ. Сами значения хранятся в замыкании,
this.from = function() { return from; };
this.to = function() { return to; };
}
// Методы прототипа не имеют прямого доступа к границам: они должны вызывать
// методы доступа, как любые другие функции и методы.
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]))
Интервал:
Закладка: