Скопировать переменное значение в другое
У меня есть переменная, которая имеет объект JSON в качестве значения. Я напрямую назначаю эту переменную какой-либо другой переменной, чтобы они имели одинаковое значение. Вот как это работает:
var a = $('#some_hidden_var').val(),
b = a;
Это работает, и оба имеют одинаковое значение. Я использую обработчик события mousemove
для обновления b
через свое приложение. При нажатии кнопки я хочу вернуть b
к исходному значению, то есть значение, сохраненное в a
.
$('#revert').on('click', function(e){
b = a;
});
После этого, если я использую один и тот же обработчик событий mousemove
, он обновляет как a
, так и b
, когда раньше он обновлял только b
, как ожидалось.
Я преувеличиваю эту проблему! Что здесь не так?
Ответы
Ответ 1
Важно понимать, что делает оператор =
в JavaScript и не делает.
Оператор =
не выполняет копирование данных.
Оператор =
создает новую ссылку на те же данные.
После запуска исходного кода:
var a = $('#some_hidden_var').val(),
b = a;
a
и b
теперь два разных имени для одного и того же объекта.
Любые изменения, внесенные вами в содержимое этого объекта, будут отображаться одинаково, ссылаетесь ли вы на него с помощью переменной a
или переменной b
. Это один и тот же объект.
Итак, когда вы позже попытаетесь "вернуть" b
к исходному объекту a
с помощью этого кода:
b = a;
Код фактически ничего не делает, потому что a
и b
- это то же самое. Код такой же, как если бы вы написали:
b = b;
который, очевидно, ничего не сделает.
Почему ваш новый код работает?
b = { key1: a.key1, key2: a.key2 };
Здесь вы создаете новый объект с литералом объекта {...}
. Этот новый объект не совпадает с вашим старым объектом. Таким образом, вы теперь устанавливаете b
в качестве ссылки на этот новый объект, который делает то, что вы хотите.
Чтобы обрабатывать любой произвольный объект, вы можете использовать функцию клонирования объекта, например, указанную в ответе Арманда, или, поскольку вы используете jQuery, просто используйте $.extend()
функция. Эта функция сделает либо мелкую копию, либо глубокую копию объекта. (Не путайте это с методом $().clone()
, который предназначен для копирования элементов DOM, а не объектов.)
Для мелкой копии:
b = $.extend( {}, a );
Или глубокая копия:
b = $.extend( true, {}, a );
Какая разница между мелкой копией и глубокой копией? Неглубокая копия похожа на ваш код, который создает новый объект с литералом объекта. Он создает новый объект верхнего уровня, содержащий ссылки на те же свойства, что и исходный объект.
Если ваш объект содержит только примитивные типы, такие как числа и строки, глубокая копия и мелкая копия будут делать то же самое. Но если ваш объект содержит другие объекты или массивы, вложенные внутри него, то мелкая копия не копирует эти вложенные объекты, а просто создает ссылки на них. Таким образом, у вас может быть такая же проблема с вложенными объектами, которые у вас были с вашим объектом верхнего уровня. Например, с учетом этого объекта:
var obj = {
w: 123,
x: {
y: 456,
z: 789
}
};
Если вы сделаете мелкую копию этого объекта, то свойство x
вашего нового объекта будет тем же самым объектом x
из оригинала:
var copy = $.extend( {}, obj );
copy.w = 321;
copy.x.y = 654;
Теперь ваши объекты будут выглядеть так:
// copy looks as expected
var copy = {
w: 321,
x: {
y: 654,
z: 789
}
};
// But changing copy.x.y also changed obj.x.y!
var obj = {
w: 123, // changing copy.w didn't affect obj.w
x: {
y: 654, // changing copy.x.y also changed obj.x.y
z: 789
}
};
Вы можете избежать этого с помощью глубокой копии. Глубинная копия повторяется во всех вложенных объектах и массивах (и Date в коде Арманда), чтобы сделать копии этих объектов таким же образом, что они сделали копию объекта верхнего уровня. Поэтому изменение copy.x.y
не повлияет на obj.x.y
.
Короткий ответ: если вы сомневаетесь, вы, вероятно, захотите получить глубокую копию.
Ответ 2
Я нашел использование JSON-работ, но смотрю наши на круглые ссылки
var newInstance = JSON.parse(JSON.stringify(firstInstance));
Ответ 3
вопрос уже решен уже довольно долгое время, но для будущей ссылки возможным решением является
b = a.slice(0);
Будьте осторожны, это работает правильно, только если a - это не вложенный массив чисел и строк
Ответ 4
Причина этого проста. JavaScript использует рефери, поэтому, когда вы назначаете b = a
, вы назначаете ссылку на b
, поэтому при обновлении a
вы также обновляете b
Я нашел этот в stackoverflow и поможет предотвратить подобные вещи в будущем, просто вызов этот метод, если вы хотите сделать глубокую копию объекта.
function clone(obj) {
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
Ответ 5
Для строк или входных значений вы можете просто использовать это:
var a = $('#some_hidden_var').val(),
b = a.substr(0);
Ответ 6
Я не понимаю, почему ответы настолько сложны. В Javascript примитивы (строки, числа и т.д.) Передаются по значению и копируются. Объекты, включая массивы, передаются по ссылке. В любом случае присвоение нового значения или ссылки на объект "a" не изменит "b". Но изменение содержимого "a" изменит содержимое "b".
var a = 'a'; var b = a; a = 'c'; // b === 'a'
var a = {a:'a'}; var b = a; a = {c:'c'}; // b === {a:'a'} and a = {c:'c'}
var a = {a:'a'}; var b = a; a.a = 'c'; // b.a === 'c' and a.a === 'c'
Вставьте любую из вышеперечисленных строк (по одному за раз) в node или любую консоль javascript браузера. Затем введите любую переменную, и консоль покажет ее значение.
Ответ 7
Я решил это сам пока. Исходное значение имеет только 2 суб-свойства. Я преобразовал новый объект со свойствами из a
, а затем назначил его b
. Теперь мой обработчик событий обновляется только b
, а мой оригинальный a
остается таким, как есть.
var a = { key1: 'value1', key2: 'value2' },
b = a;
$('#revert').on('click', function(e){
//FAIL!
b = a;
//WIN
b = { key1: a.key1, key2: a.key2 };
});
Это прекрасно работает. Я не изменил ни одной строки в моем коде, кроме вышеперечисленного, и работает так, как я этого хотел. Итак, поверьте мне, больше ничего не обновлялось a
.
Ответ 8
newVariable = originalVariable.valueOf()