Конспект JS-course

Расширение встроенных прототипов

Источник: http://learn.javascript.ru/native-prototypes

Встроенные в JavaScript объекты можно расширять и изменять. Что интересно, изменение некоторых из них повлияет и на примитивы. Можно добавить методы стандартным числам, строкам, и не только.

Конструкторы String, Number, Boolean

Строки, числа, булевы значения в JavaScript являются примитивами. Но есть также и встроенные функции-конструкторы String, Number, Boolean. Yj единственное допустимое использование этих конструкторов — запуск в режиме обычной функции для преобразования типа. Например, Number("12") преобразует в число, так же как +"12".

Автопреобразование примитивов

Несмотря на то, что в явном виде объекты String, Number, Boolean не создаются, их прототипы всё же используются. Они хранят методы строк, чисел, булевых значений. Например, метод slice для строк хранится как String.prototype.slice.

При вызове метода на примитиве, например, "строка".slice(1), происходит следующее:

  1. Примитивное значение неявно преобразуется во временный объект String.
  2. Затем ищется и вызывается метод прототипа: String.prototype.slice.
  3. Результатом вызова slice является снова примитив, а временный объект уничтожается.

Посмотрим на интересное следствие такого поведения. Попытаемся добавить свойство строке:

var hello = "Привет мир!";

hello.test = 5; // запись свойства сработала, ошибки нет...

alert(hello.test); // ...читаем свойство -- выдаёт undefined!

Будет выведено undefined, так как присвоение произошло во временный объект, созданный для обработки обращения к свойству примитива. Этот временный объект тут же уничтожился вместе со свойством.

Конечно же, браузеры при таком преобразовании применяют оптимизации и, возможно, дополнительные объекты не создаются, но логика поведения — именно такая как описана.

А значит, методы для строк, чисел, булевых значений можно изменять и добавлять свои, в прототип…

Изменение встроенных прототипов

Встроенные прототипы можно изменять. В том числе — добавлять свои методы.

Есть объекты, которые не участвуют в циклах for..in, например строки, функции… С ними уж точно нет такой проблемы, и в их прототипы, пожалуй, можно добавлять свои методы.

Но здесь есть свои «за» и «против»:

  • Методы в прототипе позволяют писать более короткий и ясный код.
  • Новые свойства, добавленные в прототип из разных мест, могут конфликтовать между собой. Представьте, что вы подключили две библиотеки, которые добавили одно и то же свойство в прототип, но определили его по-разному. Конфликт неизбежен.
  • Изменение встроенного прототипа влияет глобально, на весь код, и менять их не очень хорошо с архитектурной точки зрения.

Допустимо изменение прототипа встроенных объектов, которое добавляет поддержку метода из современных стандартов в те браузеры, где её пока нет.

Например, добавим Object.create(proto) в старые браузеры:

показать чистый исходник в новом окнеСкрыть/показать номера строкпечать кода с сохранением подсветки

if (!Object.create) {

  Object.create = function(proto) {
    function F() {}
    F.prototype = proto;
    return new F;
  };

}

Итого

  • Методы встроенных объектов хранятся в их прототипах.
  • Встроенные прототипы можно расширить или поменять.
  • Добавление методов в Object.prototype ломает циклы for..in. Другие прототипы изменять не настолько опасно, но все же не рекомендуется во избежание конфликтов.