변수의 값을 다른 값으로 복사


100

값으로 JSON 개체가있는 변수가 있습니다. 이 변수를 다른 변수에 직접 할당하여 동일한 값을 공유합니다. 작동 방식 :

var a = $('#some_hidden_var').val(),
    b = a;

이것은 효과가 있으며 둘 다 동일한 가치를 갖습니다. mousemove이벤트 핸들러를 사용하여 b내 앱 을 업데이트 합니다. 버튼을 클릭하면에 b저장된 값을 의미하는 원래 값 으로 되돌리고 싶습니다 a.

$('#revert').on('click', function(e){
    b = a;
});

그 후 동일한 mousemove이벤트 핸들러를 사용하면 a및을 모두 업데이트 하고 b이전에는 b예상 대로만 업데이트했습니다 .

나는이 문제에 대해 난처하다! 여기서 무엇이 잘못 되었습니까?


mousemove 핸들러를 보여주세요. 또한, 주어진 a에서 설정 한 .val()그 권리가있다 - 나는 그렇지 객체 JSON (문자열), 가정? JSON.parse(a)실제 물체를 얻기 위해 어떤 시점에서 사용 합니까?
nnnnnn

예, 문자열이지만 $.parseJSON객체로 변환하는 데 사용 합니다. 구조 : { 'key': {...}, 'key': {...}, ...}. 죄송합니다. 여기에 코드를 게시 할 수 없습니다. 직장에서 허용되지 않습니다!
Rutwick Gangurde 2013 년

1
그래서 a객체입니까?
Armand

1
범위 지정 문제처럼 보입니다 .. a전역 변수입니까?
msturdy

2
표시 한 코드에는 문자열 만 있습니다. 객체를 말하는 경우 여러 변수가 동일한 객체를 참조 할 수 있으므로 해당 객체는 임의의 변수를 통해 변경 될 수 있습니다. 따라서 변수를 조작하는 코드를 더 많이 보지 않고는 (어디에 $.parseJSON()들어갔습니까?) 문제가 무엇인지 말하기가 어렵습니다. 직장 규칙과 관련하여 실제 실제 코드를 전체적으로 게시 할 필요가 없습니다. 문제를 보여주는 더 짧고 일반적인 예제를 생각해보십시오 (이상적으로는 jsfiddle.net에 라이브 데모 링크 포함 ). .
nnnnnn

답변:


201

=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원하는 작업을 수행하는이 새 개체에 대한 참조로 설정 하고 있습니다.

임의의 객체를 처리하려면 Armand의 답변에 나열된 것과 같은 객체 복제 기능을 사용하거나 jQuery를 사용하기 때문에 $.extend()function을 사용하십시오 . 이 함수는 객체의 얕은 복사본 또는 깊은 복사본을 만듭니다. ( 이를 객체가 아닌 DOM 요소를 복사 하는 $().clone()방법 과 혼동하지 마십시오 .)

얕은 사본의 경우 :

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
    }
};

딥 카피로 이것을 피할 수 있습니다. 전체 복사는 모든 중첩 된 객체와 배열 (그리고 Armand의 코드에서 Date)로 반복되어 최상위 객체의 사본을 만든 것과 동일한 방식으로 해당 객체의 사본을 만듭니다. 그래서 변화 copy.x.y에 영향을주지 것입니다 obj.x.y.

짧은 대답 : 확실하지 않은 경우 딥 카피를 원할 것입니다.


감사합니다. 이것이 제가 찾던 것입니다. 이 문제를 해결할 방법이 있습니까? 내 현재 상황에서는 속성이 2 개 밖에 없기 때문에 쉽게 고칠 수있었습니다. 그러나 더 큰 물체가있을 수 있습니다.
Rutwick Gangurde 2013 년

1
Armand의 답변에는 트릭을 수행하는 객체 복제 기능이 있습니다. 또는 jQuery를 사용하고 있기 때문에 내장 $.extend()함수를 사용할 수 있습니다 . 위의 세부 사항. :-)
Michael Geary 2013 년

훌륭한 설명 마이클!
Rutwick Gangurde 2013 년

7
@MichaelGeary 그것은 nitpicking 일 수 있지만 규칙은 기본 변수가 아닌 객체에만 적용되지 않습니까? 답변에서 주목할 가치가 있습니다
Jonathan dos Santos

마이클 기어 리 말했듯 이에 JS 용액 Armands 응답 =이다.
AlexanderGriffin

57

JSON 작동 방식을 찾았지만 순환 참조를 확인하십시오.

var newInstance = JSON.parse(JSON.stringify(firstInstance));

2
이것이 조금 늦었다는 것을 알고 있지만이 방법에 문제가 있습니까? 첫 번째 시도에서 놀랍게 작동하는 것 같습니다.
Mankind1023

2
이것은 거의 모든 상황에서 훌륭하지만, 명확 할 가능성이있는 데이터로 작업하는 경우 프로그램이 중단됩니다. 설명 할 몇 가지 코드 : let a = {}; let b = {a:a}; a.b = b; JSON.stringify(a)TypeError를 줄 것 입니다.
schu34

이 솔루션은 훌륭하게 작동합니다. 그러나 처리하는 동안 비용이 얼마나 듭니까? 이것은 이중 부정으로 작동하는 것 같습니다.
Abel Callejo

30

이 문제는 꽤 오랜 시간 동안 이미 해결되었지만 향후 참조를 위해 가능한 해결책은 다음과 같습니다.

b = a.slice(0);

주의하세요. 이것은 a가 숫자와 문자열의 중첩되지 않은 배열 인 경우에만 올바르게 작동합니다.


24

newVariable = originalVariable.valueOf();

사용할 수있는 개체에 대해 b = Object.assign({},a);


3
사용할 수있는 객체의 경우 b = Object.assign ({}, a);
Kishor Patil

15

그 이유는 간단합니다. 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.");
}

감사! 나는 새 질문을 게시하기 전에 그 게시물을 보았다. 그러나 그것이 내 시나리오에서 도움이 될지 확신하지 못했습니다. 그게 내가 필요한 것임이 밝혀졌습니다.
Rutwick Gangurde 2013 년

첫 번째를 제외하고 모두가 if (obj instanceof x) { ... }아니라면 그렇지 않습니까?
Zac

@Zac이 경우에는 그렇지 않습니다. 모든 if-body (관심있는)는 값을 반환합니다. (다음 경우 이전에 기능 종료)
Bitterblue

8

나는 대답이 왜 그렇게 복잡한 지 이해하지 못한다. 자바 스크립트에서 프리미티브 (문자열, 숫자 등)는 값으로 전달되고 복사됩니다. 배열을 포함한 객체는 참조로 전달됩니다. 어쨌든 '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'

위의 행 (한 번에 하나씩)을 노드 또는 브라우저 자바 스크립트 콘솔에 붙여 넣습니다. 그런 다음 변수를 입력하면 콘솔에 값이 표시됩니다.


4

문자열 또는 입력 값의 경우 간단히 다음을 사용할 수 있습니다.

var a = $('#some_hidden_var').val(),
b = a.substr(0);

왜 프리미티브를 부분 문자열로 묶으시겠습니까? 할당 만하면 문자열이 복사됩니다. 객체와 배열 (객체) 만 참조로 전달됩니다.
Trenton D. Adams

2

여기에있는 대부분의 답변은 내장 메서드를 사용하거나 라이브러리 / 프레임 워크를 사용하는 것입니다. 이 간단한 방법은 잘 작동합니다.

function copy(x) {
    return JSON.parse( JSON.stringify(x) );
}

// Usage
var a = 'some';
var b = copy(a);
a += 'thing';

console.log(b); // "some"

var c = { x: 1 };
var d = copy(c);
c.x = 2;

console.log(d); // { x: 1 }

천재! 다른 방법은 배열을 포함하여 모든 것을 사전으로 전환합니다. 이것으로 나는 객체를 복제하고 다음과 달리 내용은 그대로 유지됩니다.Object.assign({},a)
Tiki

0

나는 당분간 직접 해결했습니다. 원래 값에는 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.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.