9.6. Приемы объектно-ориентированного программирования в JavaScript
До сих пор в этой главе мы рассматривали архитектурные основы классов в языке JavaScript: важную роль объектов-прототипов, связь классов с функциями-конструкторами, как действует оператор instanceof
и т. д. В этом разделе мы продемонстрируем несколько практических (пусть и не фундаментальных) приемов программирования на языке JavaScript с применением классов. Начнем с двух нетривиальных примеров классов, которые не только интересны сами по себе, но также послужат отправной точкой для дальнейшего обсуждения.
9.6.1. Пример: класс множества
Множество - это структура данных, представляющая неупорядоченную коллекцию неповторяющихся значений. К фундаментальным операциям над множествами относятся сложение множеств и проверка вхождения значения в множество, и обычно множества реализуются так, чтобы эти операции имели максимальную скорость выполнения. Объекты в языке JavaScript по сути являются множествами имен свойств, где с каждым именем связано некоторое значение. Таким образом, объекты легко можно использовать как множества строк. В примере 9.6 реализован более универсальный класс Set
. Он отображает любые значения, допустимые в языке JavaScript, в уникальные строки и использует их в качестве имен свойств. Объекты и функции не имеют достаточно краткого строкового представления, гарантирующего уникальность, поэтому класс Set
должен определить идентификационное свойство в любом объекте или функции, сохраняемых в множестве.
Пример 9.6. Set.js: произвольное множество значений
function Set() { // Это конструктор
this.values = {}; // Свойства этого объекта составляют множество
this.n =0; // Количество значений в множестве
this.add.apply(this. arguments); // Все аргументы являются значениями,
} // добавляемыми в множество
// Добавляет все аргументы в множество.
Set.prototype.add = function() {
for(var і = 0; і < arguments.length; i++) { // Для каждого аргумента
var val = arguments[i]; // Добавляемое значение
var stг = Set._v2s(val); // Преобразовать в строку
if (!this.values.hasOwnProperty(stг)) { // Если отсутствует в множ,
this.values[str] = val; // Отобразить строку в знач.
this.n++; // Увеличить размер множества
}
}
return this; // Для поддержки цепочек вызовов методов
};
// Удаляет все аргументы из множества.
Set.prototype.remove = function() {
for(var і = 0; і < arguments.length; i++) { // Для каждого аргумента
var str = Set._v2s(arguments[i]); // Отобразить в строку
if (this.values.hasOwnProperty(stг)) { // Если присутствует в множ,
delete this.values[str]; // Удалить
this.n--; // Уменьшить размер множества
}
}
return this; // Для поддержки цепочек вызовов методов
}
// Возвращает true, если множество содержит value; иначе возвращает false.
Set.prototype.contains = function(value) {
return this.values.has0wnProperty(Set._v2s(value));
};
// Возвращает размер множества.
Set.prototype.size = function() { return this.n; };
// Вызывает функцию f в указанном контексте для каждого элемента множества.
Set.prototype.foreach = function(f, context) {
for(var s in this.values) // Для каждой строки в множестве
if (this.values.hasOwnProperty(s)) // Пропустить унаследов. свойства
f.call(context. this.values[s]); // Вызвать f для значения
};
// Функция для внутреннего использования. Отображает любые значения JavaScript
// в уникальные строки.
Set._v2s = function(val) {
switch(val) {
case undefined: return 'u'; // Специальные простые значения
case null: return 'n'; // отображаются в односимвольные строки.
case true: return 't';
case false: return 'f;
default: switch(typeof val) {
case 'number': return + val; // Числа получают префикс #.
case 'string': return "" + val; // Строки получают префикс ".
default: return '@' + objectId(val); // Объекты и функции - @
}
}
Читать дальше
Конец ознакомительного отрывка
Купить книгу