[모던 자바스크립트 Deep Dive] 11장 - 원시 값과 객체의 비교

FE 08김우중·2022년 11월 22일
0
post-thumbnail

11 원시 타입과, 객체 타입

  • 자바스크립트가 제공하는 데이터 타입은 크게 원시 타입객체 타입으로 구분한다.

  • 그 둘의 차이점은
    - 원시 값은 변경 불가능한 값 이지만, 객체는 변경 가능한 값이다.
    - 원시 값을 변수에 할당하면 변수에는 실제 값이 저장되지만, 객체를 변수에 할당하면 변수에는 참조 값이 저장된다.
    - 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달되지만, 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달한다.

11.1 원시 값

11.1.1 변경 불가능한 값

  • 원시 타입의 값, 즉 원시 값은 변경 불가능한 값이다

  • 변수와 값은 구분해서 생각해야한다. 즉 각자의 의미를 생각해서 봤을때 변경 불가능한 것은 변수가 아니라 값에 대한 진술이다.

아래의 예시를 보고 상수와 변경 불가능한 값에대해 다시 알아보자

// const 키워드를 사용해 선언한 변수는 재할당이 금지된다. 
// 상수는 재할당이 금지된 변수일 뿐이다!!
const o = {};

// const 키워드를 사용해 선언한 변수에 할당한 원시 값(상수)은 변경할 수 없다.
// 하지만 const 키워드를 사용해 선언한 변수에 할당한 객체는 변경 가능
o.a = 1;
console.log(o); // {a: 1}

원시 값은 변경 불가능한 값이기 때문에 값을 직접 변경하지 못한다고 하였다. 즉 메모리상에서 변수 값을 변경하기 위해 원시 값을 재할당하면 새로운 메모리 공간을 확보하고 재할당한 값을 저장한 후, 변수가 참조하던 메모리 공간의 주소를 변경한다. 값의 이러한 특성을 불변성이라 한다.

11.1.2 문자열과 불변성

  • 원시 값을 저장하려면 먼저 확보해야 하는 메모리 공간의 크기를 결정해야 한다. 이를 위해 원시 타입별로 메모리 공간의 크기가 미리 정해져 있다.
// 문자열은 0개 이상의 문자로 이루어진 집합이다.
// 1개의 문자는 2바이트의 메모리 공간에 저장된다.
var st1 = ''; // 0개의 문자로 이뤄진 문자열
var str2 = 'Hello'; // 5개의 문자로 이뤄진 문자열

// 자바스크립트의 문자열은 원시 타입이며 변경 불가능하다. 즉 문자열이 생성된 이후에는 변경할 수 없음을 의미함
// 식별자 str은 문자열 'Hello'를 가리키고 있다가 문자열 'world'를 가리키도록 변경되었을뿐이다.
var str = 'Hello';
str = 'world';

// 문자열은 유사 배열 객체로 배열과 유사하게 각 문자에 접근할 수 있다.
var str = 'string';
console.log(str[0]); // s
console.log(str.length); // 6
console.log(str.toUpperCase()); // STRING

11.1.3 값에 의한 전달

변수에 변수를 할당했을 때 무엇이 어떻게 전달될까?? 아래의 예제를 살펴보자

//  변수에 원시 값을 갖는 변수를 할당하면 할당받는 변수에는 할당되는 변수의 원시 값이 복사되어 전달된다.
// 이를 값에 의한 전달이라 한다.
var score = 80;
var copy = score;

console.log(score); // 80
console.log(copy); //80

/*===================================*/

// score 변수와 copy 변수는 숫자 값 80을 갖는다는 점에서는 동일하지만
// score 변수와 copy 변수의 값 80은 다른 메모리 공간에 저장된 별개의 값이라는걸 명심하자
var score = 80
var copy = score

console.log(score, copy) // 80 80
console.log(score === copy) // true

// 서로 다른 메모리 공간에 저장된 별개의 값이므로 score 변수의 값을 변경해도 copy 변수의 값에는 어떠한 영향도 주지 않음
score = 100;
console.log(score, copy) // 100 80
console.log(score === copy) // false

사실 값에 의한 전달도 값을 전달하는 것이 아니라 메모리 주소를 전달하는것이다. 전달된 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있기때문이다. 중요한거는 변수에 원시 값을 갖는 변수를 할당하면 변수 할당 시점이든, 두 변수 중 어느 하나의 변수에 값을 재할당하는 시점이든 결국 두 변수의 원시값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값을 변경하더라도 서로 간섭할 수 없다는 것이다

11.2 객체

  • 객체는 프로퍼티의 개수가 정해져 있지 않고, 동적으로 추가되고 삭제할 수 있다. 따라서 객체는 원시 값과 같이 확보해야 할 메모리 공간의 크기를 사전에 정해 둘 수 없다.

11.2.1 변경 가능한 값

  • 객체는 변경 가능한 값이다.
// 객체를 할당한 변수가 기억하는 메모리 주소를 통해 메모리 공간에 접근하면 참조 값에 접근할 수 있다.
// 참조 값은 생성된 객체가 저장된 메모리 공간의 주소 그 자체다.
var person = {
    name: 'Lee'
}

console.log(person) // {name: 'Lee'}

/*===================================*/

// 원시 값은 변경 불가능한 값이므로 값을 변경하려면 재할당 외에는 방법이 없다.
// 하지만 객체는 변경 가능한 값이므로, 재할당 없이 객체를 직접 변경 가능하다.
// 즉 재할당 없이 프로퍼티를 동적으로 추가, 갱신, 삭제 할수도 있다.
var person = {
    name: 'Lee'
}

// 값 갱신
person.name = 'Kim'

// 동적 생성
person.address = 'Seoul'

console.log(person) // {name: "Kim", address: "Seoul"}

메모리를 효율적으로 사용하기 위해 객체는 변경 가능한 값으로 설계되어 있지만, 여러개의 식별자가 하나의 객체를 공유할 수 있다라는 부작용이있다.

// 얕은 복사와 깊은 복사
// 얕은 복사는 한 단계까지만 복사하는 것을 말하고, 깊은 복사는 객체에 중첩되어 있는 객체까지 모두 복사하는 것을 말한다.

const o = { x: { y: 1} }

// 얕은 복사
// 객체에 중첩되어 있는 객체의 경우 참조 값을 복사
const c1 = { ...o }
console.log(c1 === o) // false
console.log(cl.x === o.x) // true

// 깊은 복사
// lodash cloneDeep을 사용한 깊은 복사
// 객체에 중첩되어 있는 객체까지 모두 복사
const _ = require('lodash')

const c2 = _.cloneDeep(o)
console.log(c2 === o) // false
console.log(c2.x === o.x) // false

11.2.2 참조에 의한 전달

  • 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달되는데, 이를 참조에 의한 전달이라 한다.
// 메모리 상에서 원본 person을 사본 copy에 할당하면 원본 person 참조 값을 복사해서 copy에 저장한다.
// 다시말해 원본 person과 사본 copy는 저장된 메모리 주소는 다르지만 동일한 참조 값을가지고, 즉 동일한 객체를 가리킨다
// 이것은 두 개의 식별자가 하나의 객체를 공유한다는 것을 의미함
var person = {
    name: 'Lee'
}

// 참조값을 얕은 복사
var copy = person

console.log(copy === person) // true

// copy를 통해 객체를 변경
copy.name = 'Kim'

// person을 통해 객체를 변경
person.address = 'Seoul'

console.log(person) // {name: "Kim", address: "Seoul"}
console.log(copy) // {name: "Kim", address: "Seoul"}
profile
새내기 개발자

0개의 댓글