Книга: JavaScript. Подробное руководство, 6-е издание
9.4. Наращивание возможностей классов
9.4. Наращивание возможностей классов
Механизм наследования на основе прототипов, используемый в языке JavaScript, имеет динамическую природу: объекты наследуют все свойства своих прототипов, даже если они были добавлены в прототипы уже после создания объектов. Это означает, что в JavaScript имеется возможность наращивать возможности классов простым добавлением новых методов в объекты-прототипы. Ниже приводится фрагмент, который добавляет метод вычисления сопряженного комплексного числа в класс Complex
из примера 9.3:
// Возвращает комплексное число, которое является сопряженным
// по отношению к текущему.
Complex.prototype.conj = function() { return new Complex(this.r, -this.i); };
Объект-прототип встроенных классов JavaScript также «открыт» для подобного наращивания, а это означает, что есть возможность добавлять новые методы к числам, строкам, массивам, функциям и т. д. Данная возможность уже использовалась в примере 8.5. Там мы добавляли метод bind()
к классу функций в реализации ECMAScript 3, где он отсутствует:
if (!Function.prototype.bind) {
Function.prototype.bind = function(o /*, аргументы */) {
// Реализация метода bind...
};
}
Ниже приводятся несколько примеров расширения классов:
// Вызывает функцию f в цикле, количество итераций равно самому числу;
// при этом функции каждый раз передается номер итерации
// Например, чтобы вывести "привет" 3 раза:
// var n = 3;
// n.times(function(n) { console.log(n + " привет"); });
Number.prototype.times = function(f, context) {
var n = Number(this);
for(var і = 0; і < n; i++) f.call(context, i);
};
// Определяет метод ES5 String.trim(), если он отсутствует.
// Этот метод удаляет пробельные символы в начале и в конце строки и возвращает ее.
String.prototype.trim = String.prototype.trim || function() {
if (!this) return this; // He изменять пустую строку
return this.replace(/^s+|s+$/g, ""); // Регулярное выражение
};
// Возвращает имя функции. Если функция имеет свойство name (нестандартное),
// возвращает его значение. Иначе преобразует функцию в строку и извлекает имя из нее.
// Для неименованных функций возвращает пустую строку.
Function.prototype.getName = function() {
return this.name || this.toString().match(/functions*([^(]*)(/)[1];
};
Методы можно также добавлять в Object, prototype
, тем самым делая их доступными для всех объектов. Однако делать это не рекомендуется, потому что в реализациях, появившихся до ECMAScript 5, отсутствует возможность сделать эти дополнительные методы неперечислимыми. При добавлении новых свойств в Object.prototype
они становятся доступны для перечисления в любом цикле for/in
. В разделе 9.8.1 приводится пример использования метода Object.defineProperty()
, определяемого стандартом ECMAScript 5, для безопасного расширения Object, prototype
.
Возможность подобного расширения классов, определяемых средой выполнения (такой как веб-броузер), зависит от реализации самой среды. Во многих веб-броузерах, например, допускается добавлять методы в HTMLElement.prototype
, и такие методы будут наследоваться объектами, представляющими теги HTML в текущем документе. Однако данная возможность не поддерживается в текущей версии Microsoft Internet Explorer, что сильно ограничивает практическую ценность этого приема в клиентских сценариях.
- 24.1. Расширение возможностей Панели задач
- Глава 1 Предел возможностей иерархии в мире перемен
- 9.7.4. Иерархии классов и абстрактные классы
- 8.8.5. Шаг 4. Задание интерфейсов классов
- У14.4 Наследование без классов
- Обзор возможностей IBProvider
- Использование возможностей множества транзакций
- 3.6. Качество классов и объектов
- Соотношение классов и записей
- Обзор дополнительных возможностей защиты объектов
- Центр специальных возможностей
- Лекция № 12. Связи классов сущностей