var myArray = [1, 2, 3];
for(n in myArray) alert(n); // выводит 0, 1 и 2 - индексы массива.
Array.prototype.something = function(){ };
for(n in myArray) alert(n); // выводит 'something', 0, 1 и 2.
Как можно видеть, здесь выполнено прототипирование Array и добавлена функция something . Однако теперь эта функция something видна как элемент массива, результат, который определенно не ожидался и не требовался. То же самое происходит с объектами и объектными литералами, если выполнить прототипирование Object . Если можно быть абсолютно уверенным, что цикл for-in никогда не будет использоваться и никакой другой разработчик не будет использовать этот код JavaScript , то можно применять прототипирование для Array или Object , но надо помнить о связанных с этим проблемах. Однако существуют другие методы для достижения тех же результатов. Например, для расширения Array можно задействовать следующий метод без прототипирования:
Array.find = function(ary, element){
for(var i=0; i
if(ary[i] == element){
return i;
}
}
return -1;
}
alert(Array.find(['a', 'b', 'c', 'd', 'e'], 'b')); // выводит 1
Как можно видеть, теперь необходимо печатать Array.find(ary, e) вместо ary.find(e) , что пришлось бы делать, если прототипировать объект Array , но стоит напечатать эти несколько дополнительных символов, чтобы избежать потери существующей функциональности JavaScript .
Способ определения переменных в объекте определяет, какие методы этого объекта можно использовать для доступа к этим переменным. В JavaScript при работе с объектно-ориентированным кодом используется пять уровней методов и свойств.
1Скрытая ( Private ) - объявляется с помощью var variableName или function functionName внутри объекта. Могут быть доступны только другим скрытым или привилегированным функциям.
2Открытая ( Public ) - объявляется с помощью this.variableName внутри объекта. Может изменяться любой функцией или методом.
3Привилегированная ( Privileged ) - объявляется с помощью this.functionName = function(){ ... } внутри объекта. Доступна для любой функции или метода и может обращаться или изменять любую скрытую переменную.
4Прототипированная ( Prototype ) - объявляется с помощью Class.prototype.variableName или Class.prototype.functionName . Объявленные таким образом функции будут иметь доступ к любой открытой или прототипированной функции. Попытки изменить созданную таким образом переменную будут вместо этого создавать новую открытую переменную на объекте, а прототипированная переменная будет недоступна.
5Статическая ( Static ) - объявляется с помощью Class.variableName или Class.functionName . Может изменяться любой функцией или методом. Такой метод используется редко.
Чтобы понять различия между уровнями, давайте рассмотрим пример:
function Cat(name, color){
/*
Конструктор: при создании объекта выполняется любой находящийся здесь код
*/
Cat.cats++;
/* Скрытые переменные и функции доступны только скрытым или привилегированным
функциям. Отметим, что 'name' и 'color', переданные в Class, уже являются
скрытыми переменными.
*/
var age = 0;
var legs = 4;
function growOlder(){
age++;
}
/*
Открытые переменные доступны открыто или скрыто
*/
this.weight = 1;
this.length = 5;
/*
Привилегированные функции доступны открыто или скрыто.
Могут обращаться к скрытым переменным.
Невозможно изменить, можно только заменить открытой версией
*/
this.age = function(){
if(age==0) this.length+=20;
growOlder();
this.weight++;
}
}
/*
Прототипированные функции доступны открыто
*/
Cat.prototype = {
talk: function(){ alert('Meow!'); },
callOver: function(){ alert(this.name+' ignores you'); },
pet: function(){ alert('Pet!'); }
}
/*
Прототипированные переменные доступны открыто.
Нельзя перезаписать, только заменить открытой версией
*/
Cat.prototype.species = 'Cat';
/*
Статические переменные и функции доступны открыто
*/
Cat.cats = 0;
Мы видим, что существует несколько уровней доступа. Как было сказано ранее, все скрытые, привилегированные и открытые функции и переменные копируются всякий раз, когда создается новый экземпляр объекта. Обычно почти все, что нужно сделать, можно реализовать с помощью прототипированных и открытых переменных. В связи с этим обычно лучше избегать использования скрытых, привилегированных и статических переменных, если это не требуется специально.
Лекция 9. Наследование и замыкание
Метод наследования. Полезные (и опасные) свойства замыкания.
В восьмой лекциибыли рассмотрены основы объектно-ориентированного программирования в JavaScript . В данной лекции эта тема будет продолжена рассмотрением методов наследования, а также полезных (и опасных) свойств замыкания.
Читать дальше