다른 언어에서 값은 사용하는 구문에 따라 값(Value)복사 또는 레퍼런스(Reference)복사의
형태로 할당/전달한다.
하지만, 자바스크립트는 포인터라는 개념자체가 없고 참조하는 방법도 조금 다르다.
우선 어떤 변수가 다른 변수를 참조할 수 없다.
자바스크립트에서 레퍼런스는 (공유된)값을 가리키므로 서로 다른 10개의 레퍼런스가 있다면
이들은 저마다 항상 공유된 단일 값을 개별적으로 참조한다.
var a = 2;
var b = a; // 'b'는 언제나 'a'에서 값을 복사한다.
b++;
a; // 2
b; // 3var c = [1,2,3];
var d = c; // 'd'는 공유된 '[1,2,3]' 값의 레퍼런스다.
d.push(4);
c; // [1,2,3,4]
d; // [1,2,3,4]
주석 드래그 하면 정답 확인 가능
null, undefined, string, number, boolean, symbol 같은 단순 값은 언제나 값-복사 방식으로 할당 / 전달된다.
객체나 함수 등 합성 값은 할당 / 전달 시 반드시 레퍼런스 사본을 생성
위 예제에서 a엔 이 값의 초기 사본이 들어가고, b에는 또 다른 사본이 자리를 잡는다.
따라서 b를 바꿈으로써 a까지 동시에 값을 변경할 방법은 없다.
하지만, c와 d는 모두 합성 값이자 동일한 공유 값 [1, 2, 3]에 대한 개별 레퍼런스다.
여기서 기억해야 할 점은 c와 d가 [1, 2, 3]을 '소유'하는 것이 아니라 단지 이 값을
동등하게 참조만 한다는 사실이다.
-> 따라서, 레퍼런스로 실제 공유한 배열 값이 변경되면 (.push(4)), 이 공유 값
한 군데에만 영향을 미치므로 두 레퍼런스는 갱신된 값 [1, 2, 3, 4]를 동시에 바라보게 된다.
var a = [1,2,3];
var b = a;
a; // [1,2,3]
b; // [1,2,3]
// 그 후
b = [4, 5, 6];
a; // [1, 2, 3]
b; // [4, 5, 6]
주석 드래그 하면 정답 확인 가능
b = [4, 5, 6]으로 할당해도 a 가 참조하는 [1, 2, 3]은 영향을 받지 않는다. 그렇게 되려면 b가 배열을 가리키는 레퍼런스가 아닌 포인터가 되어야 하는데, 자바스크립트에는 포인터란 없다!
function foo(x){
x.push(4);
x;// 그 후
x = [4, 5, 6];
x.push(7);
x; // [4, 5, 6, 7];
}var a = [1, 2, 3];
foo(a);
a; // [4, 5, 6, 7]이 아닌 [1, 2, 3 , 4]
a를 인자로 넘기면 a의 레퍼런스 사본이 x에 하랃ㅇ된다. x와 a는 모두 동일한 [1, 2, 3] 값을 가리키는 별도의 레퍼런스다. 이제 함수 내부에서 이 레퍼런스를 이용하여 값 자체를 변경하던 값에는 아무런 영향이 없다. 즉, a 레퍼런스는 [1, 2, 3, 4] 값을 바라보고 있다.
레퍼런스 x로 a가 가리키고 있는 값을 바꿀 방법은 없다. 다만 a와 x 둘다 가리키는 공유 값의 내용만 바꿀 수 있다.
배ㄹ열을 새로 생성하여 할당하는 식으로는 a의 내용을 [4, 5, 6, 7]로 바꿀 수 없다. 기존에 존재하는 배열 값만 변경해야 한다.
function foo(x){
x.push(4);
x; // [1, 2, 3, 4]//그 후
x.length = 0; // 기존 배열을 즉시 비운다
x.push(4, 5, 6, 7);
x; // [4, 5, 6, 7]
}var a = [1, 2, 3];
foo(a);
a; // [1, 2, 3, 4]가 아닌 [4, 5, 6, 7]
-> x.length = 0, x.push(4, 5, 6, 7)은 새 배열을 생성하는 코드가 아니라, 이미 두 변수가 공유한 배열을 변경하는 코드이므로 a는 새로운 값 [4, 5, 6, 7]을 가리킨다.
값(Value)복사냐 레퍼런스(Reference)복사냐를 마음대로 결정할 수 없다. 전적으로 값의 타입을 보고 엔진의 재량으로 결정된다.
그렇다면 합성 값을 값(Value)복사에 의해 효과적으로 전달하려면 손수 값의 사본을 만들어 전달한 레퍼런스가 원본을 가리키지 않게 하면 된다.
foo( a.slice() );
인자 없이 slice()를 호출하면 전혀 새로운 배열(얕은 복사)의 사본을 만든다.
이렇게 보갓한 사본만을 가리키는 레퍼런스를 전달하니 foo()는 a의 내용을 건드릴 수 없다.