Скопировать переменное значение в другое

У меня есть переменная, которая имеет объект 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()