변수 선언:
var a; // 변할 수 있는 데이터를 만든다. 이 데이터의 식별자는 a로 한다.
주소 | .. | 1002 | 1003 | 1004 | 1005 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: a / 값: |
데이터 할당:
var a; // 변수 a 선언
a = 'abc'; // 변수 에 데이터 할당
var a = 'abc'; // 변수 선언과 할당을 한 문장으로 표현
변수 영역
주소 | .. | 1002 | 1003 | 1004 | 1005 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: a / 값: @5004 |
데이터 영역
주소 | .. | 5002 | 5003 | 5004 | 5005 | ... |
---|---|---|---|---|---|---|
데이터 | ‘abc’ |
1) 변수 영역에서 빈 공간 (@1003)을 확보한다.
2) 확보한 공간의 식별자를 a로 지정한다.
3) 데이터 영역의 빈 공간(@5004)에 문자열 'abc'를 저장한다.
4) 변수 영역에서 a라는 식별자를 검색한다.(@1003).
5) 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 대입한다.
불변성 예시:
var a = 'abc' // 변수 a에 'abc' 데이터 주소 할당
a = a + 'def' // 기본 'abc'에 'def' 추가가 아니라, 새로운 문자열 'abcdef'를 만들어 a에 주소 저장
// 즉, 'abc'와 'abcdef'는 완전 별개의 데이터
var b = 5; // 변수 b에 숫자 5 할당. 데이터 영역에서 5 찾고, 없으면 데이터 공간 만들어 저장
var c = 5; // b에 할당한 숫자 5의 주솟값 재활용
b = 7; // 기존 5값을 변경하지 않고, 데이터 영역에서 7을 찾거나 생성해서 주솟값 변경
참조형 데이터 할당:
var obj1 = {
a: 1,
b: 'bbb'
}
변수 영역
주소 | .. | 1002 | 1003 | 1004 | 1005 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: obj1, 값: @5001 |
데이터 영역
주소 | .. | 5001 | 5002 | 5003 | 5004 | ... |
---|---|---|---|---|---|---|
데이터 | @7103 ~ ? | 1 | ‘bbb’ |
객체 @5001의 변수 영역
주소 | .. | 7103 | 7104 | 7105 | 7106 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: a, 값: @5003 | 이름: b, 값: @5004 |
1) 컴퓨터는 변수 영역의 빈 공간(@1002)를 확보하고, 그 주소 이름을 obj1으로 지정
2) 임의의 데이터 저장공간 (@5001)에 저장하려고 보니 여러개의 프로퍼티로 이뤄진 데이터 그룹임.
이 그룹 내부의 프로퍼티를 저장하기 위해 별도의 변수 영역 마련 후, 그 영역의 주소(@7103 ~?)를 @5001에 저장
3) @7103 및 @7104에 각각 a와b라는 프로퍼티 이름 지정
4) 데이터 영역에서 숫자 1 검색.
검색 결과 없으므로 임의로 @5003에 저장하고 이 주소를 @7103에 저장.
'bbb'역시 마찬가지로 작업
가비지 컬렉터:
var a = 10;
var b = a;
var obj1 = {c: 10, d: 'ddd'};
var obj2 = obj1;
변수 영역
주소 | .. | 1001 | 1002 | 1003 | 1004 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: obj1, 값: @5001 | 이름:b, 값: @5001 | 이름: obj1, 값: @5002 | 이름: obj2, 값: @5002 |
데이터 영역
주소 | .. | 5001 | 5002 | 5003 | 5004 | ... |
---|---|---|---|---|---|---|
데이터 | 10 | @7103 ~ ? | ‘ddd’ |
객체 @5002의 변수 영역
주소 | .. | 7103 | 7104 | 7105 | 7106 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: c, 값: @5001 | 이름: d, 값: @5003 |
(1) 변수 복사 이후 값 변경 결과 비교 - 객체의 프로퍼티 변경 시
var a = 10;
var b = a;
var obj1 = {c: 10, d: 'ddd'};
var obj2 = obj1;
b = 15;
objc2.c = 20;
위 처럼 복사된 객체의 프로퍼티를 변경하면 아래와 같은 흥미로운 결과가 나온다:
a !== b
obj1 === obj2
변수 a와 b는 서로 다른 주소를 바라보게 되었으나, 변수 obj1과 obj2는 여전히 같은 객체를 바라보고 있다.
왜 그럴까?
메모리를 자세히 들여다 보면, 아래와 같이 변경이 되어있다.
변수 영역
주소 | .. | 1001 | 1002 | 1003 | 1004 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: obj1, 값: @5001 | 이름:b, 값: @5004 | 이름: obj1, 값: @5002 | 이름: obj2, 값: @5002 |
데이터 영역
주소 | .. | 5001 | 5002 | 5003 | 5004 | 5005 | ... |
---|---|---|---|---|---|---|---|
데이터 | 10 | @7103 ~ ? | ‘ddd’ | 15 | 20 |
객체 @5002의 변수 영역
주소 | .. | 7103 | 7104 | 7105 | 7106 | ... |
---|---|---|---|---|---|---|
데이터 | 이름: c, 값: @5005 | 이름: d, 값: @5003 |
var obj1 = {c: 10, d: 'ddd'};
var obj2 = obj1;
obj2 = {c:20, d:'ddd'};
왜 불변 객체가 필요할까?
var user = {
name: "Kim",
gender: "female"
}
var changeName = function(user, newName) {
var newUser = user;
newUser.name = newName;
return newUser;
}
var user2 = changeName(user, 'Jung');
console.log(user.name, user2.name) // Jung Jung
위 예시처럼 user2 호출 시, 내부 프로퍼티만 변경함으로써 기존 user 객체를 동시에 변경하였다. (가변성)
user와 user2가 다른 값을 가질 수 있도록 하려면 아래와 같이 새로운 객체를 반환하도록 수정하면 된다.
var user = {
name: "Kim",
gender: "female"
}
var changeName = function(user, newName) {
return {
name: newName,
gender: user.gender
}
}
var user2 = changeName(user, 'Jung');
console.log(user.name, user2.name) // Kim Jung
하지만, 변경된 코드의 경우 변경할 필요가 없는 기존 객체의 ‘gender’속성도 하드코딩으로 입력했다. 객체에 정보가 많을수록 비효율적이게 되는데, 프로퍼티 갯수에 상관없이 모든 프로퍼티를 복사하는 함수를 만들 수 있다.
// 얕은 복사
var copyObject = function (target) {
var result = {};
for (var prop in target) {
result[prop] = target[prop]
}
}
// 깊은 복사
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
undefined
와 null
은 자바스크립트에서 모두 ‘없음'을 나타낸다. 하지만 미세하게 차이점이 있다.undefined와 null을 구분하기 위해서는 동등 연산자 대신, 일치 연산자(===)를 사용해야 한다.
var n = null;
console.log(typeof n); // object
console.log(n == undefined); // true
console.log(n == null); // true
console.log(n === undefined); // false
console.log(n === null); // true
- 정재남, 『코어 자바스크립트』, 위키북스(2019), p1-35.