Типичные ошибки при использовании механизма наследования на базе прототипов

Как известно, объект Point не имеет совершенно никакого отношения к Dojo. Это обычный объект JavaScript типа Function. Кроме того, его не требуется инициализировать вместе с другими свойствами внутри ассоциативного массива класса Shape. В противном случае он будет вести себя как статический член класса, совместно используемый всеми объектами Shape, которые будут созданы впоследствии, и это может привести к действительно странному поведению, если только вы специально не добивались такого результата.

Проблема возникает изза того, что внутри функции declare смешиваются все свойства в прототипе объекта, а свойства прототипа совместно используются всеми экземплярами. Для таких неизменяемых типов, как числа или строки, изменение свойства приводит к изменению локальной копии. В случае изменяемых типов, таких как Object или Array, изменение свойства одного экземпляра распространяется на все экземпляры. В примере 10.7 показано, как проявляется эта проблема.

Пример 10.7. Свойства прототипа совместно используются
всеми экземплярами
function Foo() {}
Foo.prototype.bar = [100];
//Создать два экземпляра Foo
foo1 = new Foo;
foo2 = new Foo;
console.log(foo1.bar); // [100]
console.log(foo2.bar); // [100]
// Эта инструкция изменяет прототип, используемый всеми экземплярами объекта
foo1.bar.push(200);
//...поэтому изменения обнаруживаются в обоих экземплярах.
console.log(foo1.bar); // [100,200]
console.log(foo2.bar); // [100,200]

Чтобы предотвратить даже появление мысли о выполнении действий, которые могут привести к появлению ошибок, вызванных инициализацией сложных типов данных, выполняйте инициализацию всех свойств, даже инициализацию свойств простых типов, внутри стандартной функции constructor, и возьмите этот стиль программирования в привычку.


Чтобы обеспечить максимальную удобочитаемость определений ваших классов, старайтесь перечислять все свойства класса вместе с необходимыми комментариями. Чтобы продемонстрировать неприятные последствия на действующем примере, внесите следующие изменения, выделенные жирным шрифтом, в определение класса Shape и исследуйте полученные результаты в консоли Firebug:
//...обрезано...
dojo.declare("Shape", null,
{
_color: null,
//_owners: null,
_owners: [0], //это изменение превратит свойство _owners
//в статический член класса!
constructor : function(color) {
this._color = color;
//this._owners = [0];
console.log("Created a shape with color ",this._color,
" owned by ", this._owners);
},
getColor : function() {return this._color;},
addOwner : function(oid) {this._owners.push(oid);},
getOwners : function() {return this._owners;}
}
);
//...обрезано...

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Dojo на эту тему:
JavaScript – это не Java
Вызов унаследованных методов
Имитация классов с использованием средств Dojo
Множественное наследование посредством смешивания классов
Наследование в JavaScript