2013-04-28 3 views
4

자바 스크립트 객체에 대한 혼란스러운 점을 이해하려고합니다. 특히, 무엇이 객체 참조가 중단되는지 확인하는 데 관심이 있습니다.자바 스크립트 객체 참조가 초기 객체 값을 변경 한 후 깨집니다.

이 현상을 설명하기 위해 Chrome의 JavaScript 콘솔에서 출력물의 사본을 포함 시켰습니다. 여기서 배열을 다루고 있지만, JS의 배열과 객체 사이의 미묘한 차이를 고려할 때 객체가 유사하게 동작 할 것으로 기대합니다. 나는 명확성을 위해 코멘트를 추가했다. 위에서 보듯

// Set x to some array literal 
> x = [1, 2, 3, 4, 5] 
    [1, 2, 3, 4, 5] 

    // Set y to x 
> y = x 
    [1, 2, 3, 4, 5] 

> x 
    [1, 2, 3, 4, 5] // as expected 

> y 
    [1, 2, 3, 4, 5] // as expected 

모두 xy 출력과 기대 값. 이제 x의 값을 shuffle (이 질문의 맨 아래에 지정)이라는 함수를 사용하여 섞습니다.

// Shuffle x 
> x = shuffle(x) 
    [5, 1, 4, 2, 3] 

> x 
    [5, 1, 4, 2, 3] // x changes as expected 

> y 
    [5, 1, 4, 2, 3] // y changes as expected 

다시 위에서 모든 것이 예상대로 작동합니다. xy 변수는 동일한 객체에 대한 참조를 유지합니다. 그러나이 작업을 반복하면 결과가 이상합니다.

// Shuffle x 
> x = shuffle(x) 
    [3, 1, 5, 4, 2] 

> x 
    [3, 1, 5, 4, 2] // x changes as expected 

> y 
    [5, 1, 4, 2, 3] // y didn't change this time 

다음은 셔플 기능입니다 (here에서 수정). 그 목적은 배열의 내용을 섞고 (매개 변수 r1) 혼합 배열의 첫 번째 n 항목을 반환하는 것입니다.

function shuffle(r1,n) { 

    var i = r1.length, j, tempi, tempj, r2; 
    r2 = r1; 

    while (--i) { 
    j = Math.floor(Math.random() * (i + 1)); 
    tempi = r2[i]; 
    tempj = r2[j]; 
    r2[i] = tempj; 
    r2[j] = tempi; 
    } 

    return r2.slice(0,n); 
} 

this function에 따라 내 셔플 기능을 다시 작성하여 문제를 해결 이후이 있습니다. 그러나, 나는 아직도 무슨 일이 일어나고 있는지 알고 싶다. 실행중인 코드를 간단히 살펴보기 위해 jsFiddle을 만들었습니다.

아이디어가 있으십니까? 시간 내 주셔서 감사합니다.

답변

4

.slice(0,n);을 제거하면 예상 한대로 동작합니다. slice은 새 배열을 만듭니다.

처음으로 셔플을 호출하면 루프 내에서 x = y = r1 = r2 어레이가 수정됩니다. 그런 다음 마지막 줄에 복사본을 만들어 x에 할당합니다. 지금은 x !== y이지만 정확히 동일한 요소가 포함되어 있습니다. 셔플을 처음 호출 한 후 test that they are distinct objects 수 있습니다.

다음번에 shuffle을 호출하면 x의 복사본이 셔플되고 y은 변경되지 않습니다.

+0

수정 된 바이올린을 제공해 주셔서 감사합니다. – chrisfargen

+0

@chrisfargen 안녕하세요. – Paulpro

3

.slice()은 배열의 복사본을 단순화하므로 x을 새 배열로 덮어 쓰고 있습니다. (당신은 아직 슬라이스하지 않았기 때문에) y 첫 번째 셔플 을 보였다 왜

// The original was shuffled, but now `x` is a new Array 
x = shuffle(x); 

하지만, 아무도 그 이후. 후속 셔플은 덮어 쓰기 된 x에 있었고 y은 여전히 ​​원본을 참조합니다.


원래 배열을 자르려면 .length을 변경하십시오.그래서 그 대신이의

:

return r2.slice(0,n); 

이를 수행

r2.length = n; 

... 현재 n에 아무것도 통과하지 않을지라도.