1️⃣ 왜 값에 의한 전달이라고 하지 않고 “공유에 의한 전달”이라고 표현하는 것이 더 정확한지 이해한다.
2️⃣ 객체를 저장한 변수는 왜 재할당 없이 객체 자체에 직접 접근이 가능한지 이유를 이해한다.
3️⃣ 참조에 의한 전달이 위험한 이유에 대해서 명확히 이해한다.
우리는 앞서 자바스크립트 엔진은 코드의 값이 "할당"되는 실행 시점에
해당 값의 데이터 타입
을 보고 그에 맞는 메모리 크기를 할당
한다고 배웠다. (동적 타이핑)
또 이러한 데이터 타입은 총 7가지 종류(숫자,문자열,불리언,undefined, null, symbol, 객체 타입)로 나뉘어지고 크게는원시 타입(숫자~심벌)
과 객체 타입(객체, 함수, 배열 등)
두가지로 또 나뉘어진다.
한가지 궁금한 것은 분명 같은 데이터 타입임에도 불구하고 둘로 나뉘어지는 이유가 있을 텐데 그것이 무엇일까?? 각각의 타입을 보다 자세히 살펴보자.
► 원시 값은 변경 불가능한 값이다.
► 원시 값을 변수에 할당하면 변수에는 "실제 값"이 저장된다.
4장 "변수" 에서 배웠던 것들을 다시 떠올려보자...
- 변수는 "값"이 들어있는 메모리의 주소값을 갖고 있는 녀석이다. 일종의 C언어의 포인터 개념이다.
- 원시 값을 변수에 할당할 경우 해당 변수가 참조하는 메모리에는 "실제 값"이 들어있다.
- 실제 값이 저장된다고는 하지만 더 정확히는 실제 값이 "복사되어" 전달된다. 이를 값에 의한 전달이라고 한다.
"변경이 불가능하다." 라고하는 부분에 대해서 더 살펴보자.
우선 짚고 넘어가야 할 부분이 있는데 "변경이 불가능하다"라는 동사의 주체는 "값"이지 변수가 아니다.
변수는 값이 들어있는 "메모리 공간"이지 값이 아니기 때문이다.
즉 변수는 언제든지 재할당을 통해 바뀔 수 있다.
정확히 표현하면 "값"은 똑같지만 엄연히 다른 공간에 저장되어 있기에 다른 값이 되는 것이다.
아래 예제 코드를 보겠다.
var str = 'hello';
str = 'world';
원시 값인 문자열 타입을 str
이라는 변수에 할당했다.
변수를 재할당했으니 기존에 'hello'가 차지하고 있던 공간을 'world'가 대체하는 그림을 생각하겠지만 메모리 상에는 'hello'와 'world' 둘다 존재한다.
재할당되어 변하는 주체는 "값"이 아니고 "변수"이기 때문에 새로운 문자열 'world'를 메모리에 새로 생성하고 식별자 str은 새롭게 생성된 'world'의 공간을 가리키는 것이다.(C의 포인터 개념을 계속 생각하자.)
► 객체 타입은 "실제 값"을 변경할 수 있다.
► 객체를 변수에 할당하면 해당 변수(확보된 메모리 공간)에는 실제 값이 아닌 해당 객체의 주소값(참조 값)이 저장된다. 이를 참조에 의한 전달이라고 한다.
원시 값이 들어있는 변수의 값을 바꾸고 싶을 때는 재할당의 방법밖에 없었다. 하지만 객체 타입 변수에 값을 바꾸고 싶을 때에는 재할당을 하지 않고도"실제 객체 값"에 직접적인 제어가 가능하다.
예를 들면 아래와 같다.
var person = {
name : '짱구';
}
let newPerson = person;
newPerson.name = '철수';
console.log("newPerson.name"); // 철수
이것이 가능한 이유는 자바스크립트는 자체적으로 객체 메소드
라는 기능을 제공해줌으로써 값에 직접적인 제어를 허락한다.
그렇다면 자바스크립트는 왜 객체타입변수만 직접적인 제어를 허락하게끔 만들어졌을까?
이유는 메모리 효율성 때문이다.
원시 값에서 문자열이나 숫자와 같은 것들은 고정된 메모리 공간을 확보한다.(문자열은 문자마다, 숫자는 무조건 8바이트)
하지만 객체는 어떠할까? 객체는 프로퍼티의 개수도 정해져 있지 않고 사용자가 원할 때마다 동적으로 추가하고 삭제할 수 있기 떄문에 위에 문자열이나 숫자처럼 고정된 크기를 사전에 정해둘 수 없다.
애초에 객체라는 것이 사용자가 표현하고 싶은대로 표현할 수 있도록 돕는 유연한 녀석이기 때문에 객체 별로 크기가 상이하고 때로는 엄청 커질 수도 있다.
이런 객체를 또 다른 변수에 넣게 될 때 원시값 변수를 복사하는 것처럼 "값에 의한 전달" 즉 "값을 전부 복사" 하게 된다면 어떻게 될까?
메모리를 소모하는 비용이 엄청 커질 것이다.
고로 자바스크립트 자체에서 불필요한 복사가 아닌 실제 값에 직접적인 제어가 가능하도록 다른 방식으로 동작하도록 설계가 된 것이다.
var person = {
name : '짱구';
}
let person1 = person;
let person2 = person;
person1.name = '철수';
console.log("person1"); // result : 철수
person2.name = '영희';
console.log("person2"); // reuslt : 영희
console.log("person1"); // result : 영희
위에 코드를 보면 newPerson에는 객체 변수인 person이 할당되면서 참조에 의한 전달을 하였기에 같은 객체 person을 두개의 변수가 가리키고 있는 꼴이 된다.(person, copy)
두개의 변수가 모두 같은 객체의 주소를 참조하고 있기 때문에 person2의 값을 변경했음에도 불구하고 person1의 값까지 같이 변경되는 불상사를 볼 수 있다.
이렇게 예기치 못한 변수의 재할당은 오류를 추적하기 어렵게 만들고 코드의 신뢰성이 절대 좋다고 볼 수 없다.
여태껏 이야기한 것들이 다소 두서가 없고 정신사납게 이야기한 것 같아서 최대한 깔끔하게 정리를 해보겠다.
1️⃣ 왜 값에 의한 전달이라고 하지 않고 “공유에 의한 전달”이라고 표현하는 것이 더 정확한지 이해한다.
-> 원시값이 들어있는 변수를 다른 변수에 재할당되어도 변수에 저장되는 것은 원시값이 실제 저장되어 있는 메모리의 “주소값”이다. 엄연히 따지면 변수에 저장되는 것은 “실제 값”이 아닌 똑같이 “참조 값”이라는 소리이다. 단지 새로운 메모리의 주소를 할당한 것일 뿐이다. 같은 말로, 기존에 원시값이 들어있는 메모리의 주소는 공유하지 않은 것이다. 같은 말로, 복사만 했을 뿐 엄연히 다른 메모리에 존재하는 다른 값인 것이다.
-> 고로 원시값이 들어있는 변수를 재할당했을 경우 이는 “공유하지 않은 전달” 또는 “값에 의한 전달”이 되는 것이다.
2️⃣ 객체를 저장한 변수는 왜 재할당 없이 객체 자체에 직접 접근이 가능한지 이유를 이해한다.
-> 자바스크립트는 자체적으로 객체를 저장한 변수는 “(.)” 연산자를 사용하여 객체에 직접적인 접근이 가능하다. “값에 의한 전달”처럼 재할당 할 필요없이 추가하거나 삭제가 가능하다는 소리인데 이렇게 된 이유는 객체는 원시값처럼 크기가 일정하지도 않고, 또 엄청 커질 수도 있기에 값 자체를 전부 복사하기에는 메모리 효율성이 떨어진다.
3️⃣ 참조에 의한 전달이 위험한 이유에 대해서 명확히 이해한다.
-> 하나의 객체를 두개의 변수가 동일하게 가리키고 있다고 가정한다면, B변수를 참조해서 값을 변경한다고 했을 때 A변수의 값까지 같이 바뀌게 된다. 이유는 같은 주소값을 가리키고 결국 같은 값을 가리키는 변수이기 때문이다. 이렇게 될시에 의도치않은 변수의 재할당이 생길 수 있다!