09. Функции. Часть 3. Конструкторы
Расширение и модификация встроенных классов
![]() |
Не только классы, создаваемые пользователем, имеют прототипы. Их имеют и встроенные классы, такие как String, Number, Array, Date и все другие встроенные классы базового JavaScript. |
Объекты клиентского JavaScript, такие как window, document и другие, относящиеся к объектной модели браузера и объектной модели гипертекстового документа, прототипами не обладают.
Пользуясь этим, можно расширять и модифицировать (перекрывать) методы встроенных классов. Покажем на примере класса String, как это можно делать.
Добавим в прототип класса String метод delBlanks, который будет удалять из строки начальные и конечные пробелы:
String.prototype.delBlanks = function ()
{return this.replace(/^\s+|\s+$/g,'');}
Применение replace к this кажется немного странным. Но все законно! Что такое this в конструкторе String? Это ссылка на создаваемый объект. Мы не знаем имени свойства конструктора, которое содержит саму строку, поэтому используем ссылку не на неё, а на сам объект. И это проходит, ибо, когда объект используется в контексте строки, он автоматически преобразуется в строку при помощи метода toString. Значит, запись this.replace(/^\s+|\s+$/g,'') эквивалента записи this.toString().replace(/^\s+|\s+$/g, '').
Пусть программа для исполнителя Кукарача задана в виде строки. К ней теперь можно применять созданный в прототипе класса String метод delBlanks:
var str = " ВПРАВО ВЛЕВО ВНИЗ ";
str = str.delBlanks(); // "ВПРАВО ВЛЕВО ВНИЗ"
Замечание 1. Вспомним, что строки в JavaScript относятся к элементарному типу данных (то есть не являются объектами). Но всякий раз, когда в контексте работы со строками появляется объектная нотация, создается объект-обёртка — экземпляр класса String, а после выполнения операции созданный объект уничтожается.
Замечание 2. На самом деле добавление в прототипы встроенных классов новых методов, а ещё хуже, перекрытие стандартных, является плохой практикой, ибо будет вводить в заблуждения коллег, читающих наш код. Разве есть в языке такой метод для работы со строками? — Будут думать они, увидев в коде запись str.delBlanks(). Если всё же хочется дополнить прототипы встроенных классов собственными методами, не жалейте комментариев и выносите определения в начало кода, чтобы они не потерялись в его глубинах.
Рассмотрим пример работы с прототипом класса Date.
var d = new Date(); // Создали объект -- экземпляр класса Date
А теперь добавим к созданному объекту метод myGetDay, который будет возвращать день недели по-русски:
d.myGetDay = function () // Вернуть день недели по-русски
{
var dayNames = ["воскресенье", "понедельник", "вторник",
"среда", "четверг", "пятница", "суббота"];
return dayNames[this.getDay()];
}
alert(d.myGetDay()); // Получилось "воскресенье", так как я запустил
// этот код 27 июня 2010 года
Конечно, другой экземпляр, например,
var d1 = new Date();
ничего про метод объекта d не знает, и если написать:
var x = d1.myGetDay();
браузер выдаст сообщение об ошибке.
Смотрите пример «День по-русски».
А вот если добавить метод к прототипу класса Date, он станет доступен всем экземплярам этого класса.
Date.prototype.myGetDay = function () // Вернуть день недели по-русски
{
// Более компактный вариант записи кода:
return ["воскресенье", "понедельник", "вторник",
"среда", "четверг", "пятница", "суббота"][this.getDay()];
}
var d = new Date(); // Создали объект -- экземпляр класса Date
alert(d.myGetDay()); // Получилось "воскресенье"
var d1 = new Date(); // Создали объект -- экземпляр класса Date
alert(d1.myGetDay()); // И здесь получилось "воскресенье"
Смотрите пример «День по-русски 2».