Сегодня мы рассмотрим Прототипы JavaScript, но для начала вот список статей на тему «Объекты в JavaScript»:
- Объекты основанные на прототипах
- Конструкторы JavaScript
- Свойства класса JavaScript
- Наследование через цепочку прототипов
Прототипы JavaScript
Каждый объект имеет свойство prototype, указывающее на прототип, который задает структуру объекта. Это ссылка на Object, описывающий программный код и данные, которые будут общими длявсех объектов этого типа. Можно добавить в прототип конструктора программный код и данные, которыми должны обладать все объекты Robot. Для этого модифицируем наше определение следующим образом:
1 2 3 4 5 6 7 8 |
Robot.prototype.hasJetpack = false; Robot.prototype.doAction = function() { alert("Тревога! Нарушитель!"); }; function Robot (flying) if (flying == true) this.hasJetpack = true; |
Здесь было сделано несколько существенных изменений. Во-первых, мы переместили свойство hasJetpack в прототип и дали этому свойству значение по умолчанию — false. Это позволило удалить выражение esle из конструктора. Во-вторых, мы добавили в прототип конструктора функцию doAction(). Каждый создаваемый объект Robot теперь будет иметь оба свойства:
1 2 3 |
var guard = new Robot(true); var canFly = guard.hasJetpack; guard.doAction(); |
Здесь начинает проявляться сила прототипов. Мы можем получить доступ к этим двум свойствам (hasJetpack и doAction() ) через экземпляр объекта, даже если в объекте они специально не устанавливались. Как мы уже выяснили, если вызывается свойство, а объект не имеет свойства экземпляра с соответствующим именем, проверяется прототип объекта. Поэтому интерпретатор находит указанные выше свойства, хотя они и не были установлены явно. Если не сообщать аргумент конструктору Robot(), а затем попытаться получить доступ к свойству hasJetpack созданного объекта, интерпретатор найдет значение по умолчанию в прототипе. Если передать конструктору true, он отвергнет значение по умолчанию из прототипа и добавит переменную экземпляра с именем hasJetpack, значением которой будет true.
Методы могут ссылаться на экземпляр объекта, в котором они содержатся, с помощью this. Можно снова переопределить наш класс, чтобы продемонстрировать эту новую возможность:
1 2 3 4 5 6 7 8 9 10 11 |
Robot.prototype.hasJetpack = false; Robot.prototype.actionValue = "Тревога! Нарушитель!"; Robot.prototype.doAction = function() { alert(this.actionValue); }; function Robot (flying, action) { if (flying == true) this.hasJetpack = true; if (action) this.actionValue = action; } |
Мы добавили в прототип новое свойство, actionValue. Это свойство имеет значение по умолчанию, которое может быть переписано с помощью передачи конструктору второго аргумента. Если конструктору передается значение для action, то вызов doAction () покажет именно это значение, а не значение по умолчанию («Тревога! Нарушитель ! «). Например, в результате
1 2 |
var guard - new Robot(true, "БАХ!"); guard.doAction(); |
будет показано «БАХ! «, а не «Тревога! Нарушитель ! «.
Динамические типы
Очень важным аспектом понятия прототипа является то, что он является общим. Это значит, что имеется только одна копия прототипа, которую используют все объекты, созданные с помощью одного конструктора. Следствием является то, что изменение в прототипе будет видимым для всех объектов, совместно использующих этот прототип! Именно поэтому значение по умолчанию в прототипе заменяется переменными экземпляра, а не изменяются непосредственно. Изменение их в прототипе должно изменить соответствующее значение для всех объектов, совместно использующих этот прототип.
Изменение прототипов встроенных объектов может оказаться очень полезным. Предположим, что вам часто приходится извлекать из строк третий символ. Можно изменить прототип объекта String так, чтобы все строки имели определенный вами метод:
1 2 3 4 |
String.prototype.getThirdChar = function() { return this.charAt(2); } |
После этого вы можете вызывать этот метод точно так же, как любой встроенный метод объекта String:
1 |
var с = "Пример".getThirdChar(); // значением с будет 'и' |