2013-11-11 6 views
2

Я не уверен, как это объяснить, и это ДЕЙСТВИТЕЛЬНО беспокоит меня. Это испортит мой код. Во всяком случае, здесь в основном то, что есть. Предположим, у меня есть переменная, которая держит на структуру с некоторыми значениями, скажем, настройки по умолчанию:JavaScript Переменные, записывающие другие переменные без инструкции?

var DefaultValues = { 
    username: "cakeisajoke", 
    this: "is some", 
    default: { 
     data: 483 
    }, 
    lives: 3, 
    playerX: 0, 
    playerY: 0 
} 

В моем коде, я использую эту переменную как «шаблон», так что я могу сбросить свою игру проще. Например:

var GameValues = DefaultValues; 

Хорошо, так что имеет смысл до сих пор. Теперь, скажем, игрок теряет жизнь:

GameValues.lives--; 

Либо игрок перемещает некоторые из них:

GameValues.playerX += 20; 
GameValues.playerY -= 10; 

Итак, теперь мой GameValues ​​меняется, и я поставил игру на это. Но тогда игрок терпит неудачу и получает игру. Если он хочет играть снова, все, что нужно сделать, это сбросить переменную GameValues ​​к значениям по умолчанию:

GameValues = DefaultValues; 

И, насколько я обеспокоен, это надо просто набор GameValues ​​к DefaultValues, верно? Но это не так. По какой-то причине GameValues ​​и DefaultValues ​​теперь имеют одинаковые значения, если они не должны. Например, DefaultValues ​​теперь 0, вместо того, что было изначально, 1.

Почему это делается? Я посмотрел и снова посмотрел, и я НЕ устанавливаю DefaultValues ​​в любом месте кода, кроме этой начальной структуры.

«Я использовал это и по умолчанию в качестве примера, я знаю, что я не могу на самом деле использовать их, так как они защищены»

+1

Я бы *** сильно *** рекомендую не использовать 'this' как имя свойства. –

ответ

1

Это потому, что Javascript использует ссылки на объекты. Поэтому назначение объекта другому объекту просто заставляет их указывать на один и тот же объект. Вам нужно клонировать объект, поток this описывает несколько способов сделать это.

var GameValues = DefaultValues; //Both variables reference the same object 
GameValues.lives--; //Since they both reference the same object this will change both the variables so to say 

Также рассмотреть не используя слова this и default как ключи, они являются зарезервированными ключевыми словами.

+0

Работал. Потребовалось немного, так как node-webkit не понял .clone(), но в итоге он работал. – pjrader1

+0

Какое решение вы использовали? –

+0

Я использовал http://stackoverflow.com/a/122190/1457856 в конце, хотя я изначально пробовал http://stackoverflow.com/a/2469611/1457856 – pjrader1

0

Когда вы делаете назначение var a = {}, магазины JavaScript в a ссылкой на вновь созданный объект, а не его значение, поэтому при изменении параметров с помощью GameValues, настройки в DefaultValues также меняются: те два являются ссылки на тот же объект.

При инициализации новой переменной примитивного типа, такие как var i = 1;, он хранит в i фактическое значение так

var i = 1; 
var b = i; 
var b += 4; // b is 5, i is still 1 

Чтобы решить конкретную задачу, вы можете написать рекурсивную функцию, которая будет пересекать объект, и сделайте копию каждой пары ключ-значение. См. this article, он должен предоставить вам некоторые сведения о том, как это сделать.

0

Поскольку DefaultValues является объектом, когда вы назначаете его GameValues вы на самом деле просто назначая ссылку к нему, а не копирует сам объект. Это означает, что когда вы устанавливаете свойство одного, это изменение будет отражено в другом.

Вы можете обойти это, скопировав свойства с DefaultValue на GameValue вместо того, чтобы делать это в одном задании. Вот простой пример, но обратите внимание, что вам придется обрабатывать вложенные объекты тоже:

Object.keys(DefaultValues).forEach(function (key) { 
    GameValues[key] = DefaultValues[key]; 
}); 
+0

На самом деле это неверно, вам нужно рекурсивно позвонить метод на любой предмет, где typeof === "object" –

+0

@HugoTunius - хорошая точка. Код в ответе - всего лишь пример. Это должно послужить хорошей отправной точкой для работы OP. –

+0

Ах, хорошо, просто не хочу, чтобы он копировал его напрямую и получал более странные проблемы. –

1

Ваш текущий вопрос из-за javascript uses references for objects.

Для этого царя подход можно использовать другие модели JS, как этот

var DefaultValues = { 
    username: "cakeisajoke", 
    "this" : "is some", 
    default: { 
     data: 483 
    }, 
    lives: 3, 
    playerX: 0, 
    playerY: 0 
} 

var GameValues = Object.create(DefaultValues); 

и вы можете сделать

GameValues.lives--; 
GameValues.playerX += 20; 
GameValues.playerY -= 10; 

с вне изменения defalut.

Его стоит посмотреть на эту modeling-patterns-for-javascript-browserbased-games

+0

'Object.create' не поддерживается в некоторых старых браузерах, это нужно проверить и обработать, если вы собираетесь его использовать. –

1

При создании DefaultValues объекта, вы создаете объект в памяти, и ссылка к этому объекту, который находится в вашей DefaultValues переменной:

+---------------+    +-------------------------+ 
| DefaultValues |--------------->| username: "cakeisajoke" | 
+---------------+    | lives: 3    | 
           | (and so on)    | 
           +-------------------------+

когда вы делаете это:

var GameValues = DefaultValues; 

вы дзю st сохраняя ссылку на объект во второй переменной. Теперь у вас есть это:

+---------------+ 
| DefaultValues |---+ 
+---------------+ |   +-------------------------+ 
        |   | username: "cakeisajoke" | 
        +----------->| lives: 3    | 
        |   | (and so on)    | 
+---------------+ |   +-------------------------+ 
| GameValues |---+ 
+---------------+

Вы не имеете копию из DefaultValues, вы только две ссылки на объект. Изменения, которые вы делаете, чтобы объект менял объект, и поэтому естественно видны независимо от того, какую ссылку вы используете.

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