과거에는 메모리 용량이 제한적이었기 때문에 작은 크기의 정수형 타입(short 등)을 사용하여 메모리를 절약했다. 하지만 특정 범위를 벗어나는 값이 입력되면 오류가 발생하거나 잘못된 값이 저장되는 문제가 있었다. 이를 해결하기 위해 사용자가 직접 형변환을 해야 했다.
현대의 자바스크립트와 같은 프로그래밍 언어는 메모리 용량이 훨씬 커졌기 때문에 이러한 메모리 제약이 크게 줄었다. 숫자형 데이터의 크기에 대한 걱정이 덜해졌고, 대부분의 경우에는 64비트, 즉 8바이트를 사용하여 숫자를 저장한다. 그래서 형변환이나 메모리 제약과 같은 문제를 걱정할 필요가 없어졌다.
모든 데이터는 바이트 단위의 식별자 (메모리 주솟값)을 통해 서로 구분하고 연결할 수 있다.
변수: 변할 수 있는 수(변경 가능한 데이터가 담길 수 있는 공간)
식별자: 어떤 데이터를 식별하는 데 사용하는 이름 (변수명)
변수 영역: 변수와 상수를 구분 짓는 곳
데이터 영역: 불변성 여부를 구분하는 곳
var a = 'abc'
var obj 1 = {
a: 1 ,
b: 'bbb'
};
참조형은 객체의 변수 영역이 별도로 존재한다. 객체가 별도로 할애한 영역은 변수 영역일 뿐 데이터 영역은 기존의 공간의 메모리 공간을 그대로 활용하고 있다.
변수에는 다른 값을 얼마든지 대입할 수 있기 때문에 참조형은 가변값이라고 하는 것이다.
- 구조화된 메모리 관리
프로그램의 변수와 데이터를 각각의 목적에 맞게 분리하여 메모리를 효율적으로 관리할 수 있다.
- 변수와 데이터의 독립성 유지
변수와 데이터가 분리되면 변수에 대한 수정이 데이터에 영향을 미치지 않으며, 데이터의 변경이 변수에 영향을 주지 않는다.
var name = '보'
name = name + '미'
변수name에 문자열 '보' 를 할당했다가 뒤에 '미'를 추가하면 기존의 '보'가 '보미'로 바뀌는 것이 아니라 새로운 문자열 '보미'를 만들어 그 주소를 변수에 저장한다.
-> '보'와 '보미'는 완전히 별개의 데이터!
-> 주소가 다르다고 생각하자.
변수영역에 name이 생기고, 데이터 영역의 (예를 들어) 5003에 보가 저장되어있는 것이고, 나중에 보미라는 문자열이 5004에 저장되는 것. 그래서 변수영역의 값이 5003에서5004로 바뀐다는 뜻.
let person = { name: '보미' };
person.name = '보라'; // 객체 내의 속성 값 변경 가능
// 기본형 데이터 (원시형)
let num1 = 10; // 숫자
let str1 = "Hello"; // 문자열
// 변수에 복사된 값 확인
let copiedNum1 = num1;
let copiedStr1 = str1;
// 변수의 값 변경
num1 = 20;
str1 = "World";
// 변수의 값과 복제된 값 출력
console.log(num1); // 20
console.log(copiedNum1); // 10
console.log(str1); // "World"
console.log(copiedStr1); // "Hello"
// 참조형 데이터 (객체형)
let obj1 = { name: "John", age: 30 }; // 객체
let arr1 = [1, 2, 3, 4, 5]; // 배열
// 변수에 복사된 값 확인
let copiedObj1 = obj1;
let copiedArr1 = arr1;
// 변수의 값 변경
obj1.name = "Jane";
arr1.push(6);
// 변수의 값과 복제된 값 출력
console.log(obj1); // { name: "Jane", age: 30 }
console.log(copiedObj1); // { name: "Jane", age: 30 }
console.log(arr1); // [1, 2, 3, 4, 5, 6]
console.log(copiedArr1); // [1, 2, 3, 4, 5, 6]
불변 객체: 한 번 생성되면 그 상태를 변경할 수 없는 객체
값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우가 있다.
// 가변성으로 인한 문제점
const obj1 = { value: 10 };
const obj2 = obj1;
obj1.value = 20;
console.log(obj2.value); // 출력 결과: 20
obj1과 obj2가 동일한 객체를 가리키고 있다.
해결책)
const obj1 = { value: 10 };
// 객체의 프로퍼티를 복사하여 새로운 객체 생성
const obj2 = { ...obj1 };
obj1.value = 20;
console.log(obj2.value); // 출력 결과: 10
obj1을 복사하여 새로운 객체를 만든다.
// 얕은 복사 예시
// 원본 객체
const originalObj = {
name: '보미',
age: 25,
address: {
city: '서울',
country: '대한민국'
}
};
// 얕은 복사
const shallowCopyObj = { ...originalObj };
// 원본 객체와 얕은 복사된 객체의 주소 확인
console.log(originalObj === shallowCopyObj); // false
// 내부 객체의 주소 확인
// 내부 객체인 address는 얕은 복사되어 참조로 복사되었기 때문에 동일한 메모리 주소를 가짐
console.log(originalObj.address === shallowCopyObj.address); // true
// 내부 객체 변경
originalObj.address.city = '제주도';
// 얕은 복사된 객체의 내부 객체도 변경되었는지 확인
// originalObj의 address 객체를 변경 -> shallowCopyObj.address도 같은 객체를 참조하고 있기 때문에 shallowCopyObj 객체에서 address 객체의 변화가 반영됨
console.log(shallowCopyObj.address.city); // 제주도
// 원본 객체
const originalObj = {
name: '보미',
age: 25,
address: {
city: '서울',
country: '대한민국'
}
};
// 깊은 복사
const deepCopyObj = JSON.parse(JSON.stringify(originalObj));
// 원본 객체와 깊은 복사된 객체의 주소 확인
console.log(originalObj === deepCopyObj); // false
// 내부 객체의 주소 확인
console.log(originalObj.address === deepCopyObj.address); // false
// 내부 객체 변경
originalObj.address.city = '제주도';
// 깊은 복사된 객체의 내부 객체가 변경되었는지 확인
console.log(deepCopyObj.address.city); // 서울
// 변수 선언만 하고 초기화되지 않은 경우
let undefinedVariable;
let nullVariable = null;
// 값이 없음을 나타내는 변수에 대한 비교
console.log(undefinedVariable === undefined); // true
console.log(nullVariable === null); // true
// undefined와 null 비교
// 서로 다른 데이터 타입이므로 === 비교 연산자를 사용하여 비교할 때 false 반환
console.log(undefined === null); // false