학습목표
자바스크립트가 데이터를 처리하는 과정을 살펴봄으로써 기본형 타입과 참조형 타입이 서로 다르게 동작하는 이유를 이해하고, 이를 적절히 활용할 수 있다.
모든 데이터는 바이트 단위의 식별자, 더 정확하게는 메모리 주솟값을 통해 서로 구분하고 연결할 수 있다.
변수 : 변할 수 있는 무언가 (데이터)
식별자: 어떤 데이터를 식별하는 데 사용하는 이름 (변수명)
var a; // 메모리에서 비어있는 공간 하나를 확보하고, 이 공간의 이름을 a라고 지정한다.
var a; // 변수 a 선언
a = 'abc'; // 변수 a에 데이터 할당
var a = 'abc'; // 변수 선언과 할당을 한 문장으로 표현
데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위함이다.
효율적으로 문자열 데이터의 변환을 처리하려면 변수와 데이터를 별도의 공간에 나누어 저장하는 것이 최적이다.
특히 중복된 데이터에 대한 처리 효율이 높아진다.
a = 'abcdef'; // a의 마지막에 def를 추가
✔️ 기존 문자열에 어떤 변환을 가하든 상관없이, 무조건 새로 만들어 별도의 공간에 저장하고 그 주소를 변수 공간에 연결한다.
바꿀 수 있으면 변수, 바꿀 수 없으면 상수
변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리이다.
한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당 할 수 있는지 여부가 관건이다.
불변성 여부를 구분할 때의 변경 가능성의 대상은 데이터 영역의 메모리이다.
✔️ 기본형 데이터인 숫자, 문자열, boolean, null, undefined, Symbol은 모두 불변값이다.
문자열 값도 숫자 값도 한 번 만든 값을 바꿀 수 바꿀 수 없다.
변경은 새로 만드는 동작을 통해서만 이뤄진다.
한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않는다.
var obj1 = {
a: 1,
b: 'bbb'
};
1. 변수 영역의 빈 공간(@1002)을 확보하고 그 주소의 이름을 obj1로 지정
2. 임의의 데이터 저장 공간(@5001)에 데이터를 저장하려 보니 여러 개의 프로퍼티로 이루어진 데이터 그룹 -> 별도의 변수 영역을 마련 후 그 영역의 주소(@7103 ~?)를 @5001에 저장
3. @7103, @7104에 각각 a,b 프로퍼티 이름을 지정
4. 데이터 영역에서 숫자 1을 임의로 @5003에 저장하고 이 주소를 @7103에 저장, 문자열 'bbb' 역시 임의로 @5004에 저장하고 이 주소를 @7104에 저장
✔️ 기본형 데이터와의 차이는 '객체의 변수(프로퍼티) 영역'이 별도로 존재한다는 점이다.
var obj1 = {
a: 1,
b: 'bbb'
};
obj1.a = 2;
✔️ 새로운 객체가 만들어진 것이 아니라 기존 객체 내부의 값만 바뀐다.
var obj = {
x: 3,
arr: [3, 4, 5]
};
1. 변수 영역의 빈공간(@1002) 확보 후 주소의 이름을 obj로 지정
2. 임의의 데이터 저장공간(@5001)에 객체의 변수영역 주소(@7103~?)를 저장
3. @7103에 이름 x, @7104에 이름 arr를 저장
4. 숫자 3을 임의로 @5002에 저장 후 이 주소를 @7103에 저장
5. 임의의 데이터 저장공간(@5003)에 배열의 변수영역 주소(@8103~?)를 저장
6. 배열의 요소 개수 만큼 변수공간을 확보하고 각각 인덱스를 부여
7. 숫자를 검색해서 그 주소를 배열의 변수 영역에 저장하거나, 임의의 데이터 영역에 저장 후 그 주소를 배열의 변수 영역에 저장.
var a = 10;
var b = a;
var obj1 = {c: 10, d: 'ddd'};
var obj2 = obj1;
var a = 10;
var b = a;
var obj1 = {c: 10, d: 'ddd'};
var obj2 = obj1;
b = 15;
obj2.c = 20;
a !== b
obj1 === obj2
💡 기본형 데이터와 참조형 데이터의 가장 큰 차이점
- 기본형 데이터는 주솟값을 복사하는 과정이 한 번만 이뤄지고, 참조형 데이터는 한 단계를 더 거치게 된다.
- 참조형 데이터가 '가변값'이라고 설명할 때의 '가변'은 참조형 데이터 자체를 변경할 경우가 아니라 그 내부 프로퍼티를 변경할 때만 성립한다.
var user = {
name: 'Jaenam',
gender: 'male'
};
var changeName = function (user, newName) {
var newUser = user;
newUser.name = newName;
return newUser;
};
var user2 = changeName(user, 'Jung');
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // Jung Jung
console.log(user === user2); // true
var user = {
name: 'Jaenam',
gender: 'male'
};
var changeName = function (user, newName) {
return {
name: newName,
gender: user.gender
};
};
var user2 = copyObject(user); // 얕은 복사만 수행한다.
user2.name = 'jung';
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.'); // 유저 정보가 변경되었습니다.
}
console.log(user.name, user2.name); // Jaenam Jung
console.log(user === user2); // false
얕은 복사
중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사한다.
즉 해당 프로퍼티에 대해 원본과 사본이 모두 동일한 참조형 데이터의 주소를 가리키게 된다.
따라서, 사본을 바꾸면 원본도 바뀌고 원본을 꾸면 사본도 바뀐다.
깊은 복사
어떤 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때 사용한다.
객체의 프로퍼티 중 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되지만 참조형 데이터는 다시 그 내부의 프로퍼티들을 복사해야 한다.
이 과정을 참조형 데이터가 있을 때마다 재귀적으로 수행해야만 비로소 깊은 복사가 된다.
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) { // typeof가 null 도 object로 반환하기 때문
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
else {
result = target;
}
return result;
};
var copyObjectViaJSON = function (target) {
return JSON.parse(JSON.stringify(target));
}
undefined
사용자가 명시적으로 지정할 수도 있지만 (비추천), 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여한다.
[1] 값을 대입하지 않은 변수. 즉 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
[2] 객체 내부의 존재하지 않는 프로퍼티에 접근하려고 할 때
[3] return 문이 없거나 호출되지 않는 함수의 실행 결과
null
비어있음을 명시적으로 나타내고 싶을 때 사용.
끝😇