2014-05-20 3 views
2

У меня возникли проблемы с поиском способа предотвратить случайные изменения прототипа объекта. Приведенный ниже пример поможет прояснить мой вопрос:Предотвращение случайного изменения прототипа javascript

var Enemy, enemy1, enemy2; 

Enemy = (function() { 
    function Enemy() {} 

    Enemy.prototype.speed = 10; 

    Enemy.prototype.stats = { 
    strength: 15 
    dexterity: 12 
    }; 

    return Enemy; 

})(); 

enemy1 = new Enemy(); 
enemy2 = new Enemy(); 

enemy1.speed = 20; 
enemy1.stats.strength = 25; 

console.log("enemy1 speed: " + enemy1.speed); 
console.log("enemy2 speed: " + enemy2.speed); 
console.log("enemy1 str: " + enemy1.stats.strength); 
console.log("enemy2 str: " + enemy2.stats.strength); 

Результат:

console: enemy1 speed: 20 
console: enemy2 speed: 10 
console: enemy1 str: 25 
console: enemy2 str: 25 

Как вы можете видеть, редактировать примитивного свойства на enemy1 (например speed) не влияет на enemy2. Но когда свойство внутри свойства объекта изменяется на враге1 (например, stats.strength), это, по-видимому, фактически изменяет прототип вместо экземпляра.

Я считаю, что это происходит потому, что ни enemy1, ни enemy2 имеют локальное свойство под названием stats, так enemy1.stats преобразуется в значение прототипа, а это означает, что его значение для strength изменяется.

Я придумал способ решить эту проблему, изменив конструктор врага:

function Enemy() { 
    //using jQuery to deep copy the stats property in the prototype 
    this.stats = $.extend(this, Enemy.prototype.stats); 
} 

Это инициализирует локальное свойство статистики, что означает ссылку на enemy1.stats больше не ссылается на прототипе.

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

Есть ли лучший подход, который я могу использовать здесь?

Спасибо!

+1

Похоже, вы хотите, чтобы 'speed' и' stats' были * конкретными свойствами * экземпляра *, поэтому вы должны инициализировать эти значения в функции конструктора. –

ответ

2

Это, по-видимому, фактически изменяет прототип вместо экземпляра.

Нет, это изменяет объект, на который ссылается прототип. Но это происходит почти так же. :-)

Я считаю, что это потому, что ни у врага1, ни у врага2 нет локального свойства, называемого статистикой, поэтому враг1.stats переходит к значению прототипа, что означает, что его значение для силы изменяется.

Точно, да. (Терминология - это «собственная» собственность, а не «местная» собственность, но у вас это точно.)

Есть ли лучший подход, который я могу использовать здесь?

Я думаю, что у вас есть хороший подход. Если бы вы хотели, вы могли бы автоматизировать его (прокручивая свойства по this и для любых typeof как "object", пропустив их через extend), но в корне, если вы собираетесь изменять свойства объектов, связанных с экземпляром, эти объекты должны быть на экземпляре, а не на прототипе.

FWIW, я, вероятно, не имел бы stats на прототипе вообще, только в конструкторе.

Смежные вопросы