Я пытаюсь определить класс JavaScript со свойством массива и его подкласс. Проблема состоит в том, что все экземпляры подкласса так или иначе "совместно используют" свойство массива:
// class Test
function Test() {
this.array = [];
this.number = 0;
}
Test.prototype.push = function() {
this.array.push('hello');
this.number = 100;
}
// class Test2 : Test
function Test2() {
}
Test2.prototype = new Test();
var a = new Test2();
a.push(); // push 'hello' into a.array
var b = new Test2();
alert(b.number); // b.number is 0 - that's OK
alert(b.array); // but b.array is containing 'hello' instead of being empty. why?
Поскольку Вы видите, что у меня нет этой проблемы с примитивными типами данных... Какие-либо предложения?
Когда вы пишете Test2.prototype = new Test ()
, вы создаете единственный экземпляр Test
с одним экземпляром массива, который используется совместно каждым экземпляром Test2
.
Следовательно, все экземпляры Test2
используют один и тот же массив.
Вы можете решить эту проблему, вызвав конструктор base Test
из конструктора Test2
, который создаст новый экземпляр массива для каждого экземпляра Test2
.
Например:
function Test2() {
Test.call(this);
}
Другая, довольно неэлегантная альтернатива - перенести код инициализации из конструктора в метод и вызывать его из обоих конструкторов:
// class Test
function Test() {
this.init();
}
Test.prototype.init = function() {
this.array = [];
this.number = 0;
};
Test.prototype.push = function() {
this.array.push('hello');
this.number = 100;
};
// class Test2 : Test
function Test2() {
this.init();
}
Test2.prototype = new Test();
Я могу думать только о том, что массивы - это общие ссылки. Должно быть очевидное решение, поскольку такой классический код ООП постоянно реализуется в Javascript.
JavaScript не имеет классической системы наследования, он имеет прототипическую систему наследования. Поэтому в JavaScript технически не существует понятия "Класс".
Объекты наследуются от других объектов (так называемый прототип объекта), а не от абстрактных классов. Одним из важных последствий этого является то, что если несколько объектов имеют один и тот же прототип и один из этих объектов изменяет атрибут, определенный в прототипе, то это изменение немедленно вступает в силу для всех остальных объектов.
Попытка использовать наследование JavaScript так, как если бы оно было основано на классах, обычно вызывает большую головную боль, потому что вы постоянно сталкиваетесь с такого рода проблемами.
Я знаю, что это не совсем отвечает на ваши конкретные вопросы, но на высоком уровне я рекомендую вам принять прототипическое наследование вместо того, чтобы пытаться использовать "псевдоклассы". Даже если поначалу это выглядит странно, ваш код будет намного надежнее, и вы не будете терять время, пытаясь понять странные ошибки вроде этой, вызванные странной цепочкой прототипов.
Посмотрите это видео, где Дуглас Крокфорд объясняет наследование, оно доступно онлайн на сайте Yahoo UI Theater. Оно изменило мой подход к программированию на JavaScript :)
http://video.yahoo.com/watch/111585/1027823 (ссылка на первую часть)
http://developer.yahoo.com/yui/theater/ (для всех видео)