모던 JS DeepDive(11장)

Minji Lee·2024년 1월 23일
0
post-thumbnail

[11장] 원시 값과 객체의 비교

JS가 제공하는 7가지 데이터 타입

⇒ 문자열, 숫자, 불리언, null, undefined, 심벌, 객체 타입

원시 타입객체 타입
변경 불가능한 값변경 가능한 값
원시 값 변수에 할당 시, 실제 값저장객체를 변수에 할당 시, 참조 값 저장
원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달 ⇒ 에 의한 전달객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달 ⇒ 참조에 의한 전달

11.1 원시 값

11.1.1 변경 불가능한 값

원시 타입의 값, 즉 원시 값은 변경 불가능한 값 ⇒ 읽기 전용(read only) 값으로서 변경 불가능

❗️원시 값 자체를 변경할 수 없다는 것! 변수 값을 변경할 수 없다는 것이 아님!

  • 원시 값을 할당한 변수에 새로운 원시 값을 재할당하면 메모리 공간에 저장되어 있는 재할당 이전의 원시 값을 변경하는 것이 아니라, 새로운 메모리 공간을 확보하고 재할당한 원시 값 저장한 후, 변수는 새롭게 재할당한 원시 값 가리킴메모리 주소 바뀜(불변성)
  • 불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 방법 X
  • 변수 vs 상수
    변수
    : 언제든지 재할당을 통해 변수 값 변경 가능
    상수: 단 한번만 할당이 허용되어 변수 값 변경 불가능 → 재할당 금지된 변수
     // const 키워드를 사용해 선언한 변수는 재할당 금지
     const o = {};
     
     // const 키워드를 사용해 선언한 변수에 할당한 원시 값(상수)는 변경 불가능
     // 하지만 const 키워드 사용해 선언한 변수에 할당한 객체는 변경 가능
     o.a = 1;
     console.log(o); // {a: 1}
     ```
     
  • 원시 값은 어떤 일이 있어도 불변하므로 데이터 신뢰성 보장

11.1.2 문자열과 불변성

문자열: 0개 이상의 문자로 이뤄진 집합, 1개의 문자는 2바이트의 메모리 공간에 저장

  • 다른 원시 값과 달리 몇 개의 문자로 이루어 졌느냐에 따라 메모리 공간의 크기가 결정
  • 문자열은 유사 배열 객체이면서 이터러블이므로 배열과 유사하게 각 문자에 접근 가능

    유사 배열 객체
    마치 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있고 length 프로퍼티를 갖는 객체

    var str = 'string';
    
    // 문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 각 문자에 접근 가능
    console.log(str[0]); // s
    
    // 원시 값인 문자열에 객체처럼 동작
    console.log(str.length); // 6
    consoel.log(str.toUpperCase()); // STRING
  • 이미 생성된 문자열의 일부 문자는 변경해도 반영 안됨!
    var str = 'string';
    
    str[0] = 'S';
    
    console.log(str); // string
  • 변수에 새로운 문자열을 재할당하는 것은 가능

11.1.3 값에 의한 전달

var score = 80;
var copy = score;

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

score = 100;

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

변수에 원시 값을 갖는 변수를 할당하면 할당받는 변수에는 할당되는 변수의 원시 값이 복사되어 전달됨 ⇒ 값에 의한 전달

  • score 변수와 copy 변수의 값 80은 다른 메모리 공간에 저장된 별개의 값

  • 따라서, score 변수 값을 변경해도 copy 변수의 값에는 어떠한 영향도 주지 않음

    var score = 80;
    
    // copy 변수에는 score 변수의 값 80이 복사되어 할당됨
    var copy = score;
    
    console.log(score, copy); // 80 80
    console.log(score === copy); // true
    
    // score 변수와 copy 변수의 값은 다른 메모리 공간에 저장된 별개의 값
    // 따라서 score 변수의 값을 변경해도 copy 변수의 값에는 어떠한 영향 주지 않음
    score = 100;
    console.log(score, copy); // 100 80
    console.log(score === copy); // false

    ❗️ 실제 JS 엔진 내부 동작과 정확히 일치하지 않을 수 있음(두 가지 평가 방식 존재)

    1. 값에 의해 전달된 값은 다른 메모리 공간에 저장된 별개의 값

    2. 변수에 원시값을 갖는 변수를 할당하는 시점에는 두 변수가 같은 원시 값을 참조하다가 어느 한쪽의 변수에 재할당이 이뤄졌을 때 비로소 새로운 메모리 공간에 재할당된 값을 저장하는 경우

  • “값에 의한 전달” 이라는 용어는 자바스크립트를 위한 용어가 아님! ⇒ 변수에는 값이 전달되는 것이 아니라 메모리 주소가 전달되기 때문에 변수와 같은 식별자는 값이 아니라 메모리 주소를 기억하고 있음

  • ⭐️ 어쨋든, 중요한 것은 두 변수의 원시 값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값을 변경하더라도 서로 간섭할 수 없음


11.2 객체

[객체 특징]

  • 프로퍼티의 개수가 정해져 있지 않음 → 동적으로 추가, 삭제 가능
  • 프로퍼티의 값에 제약 없음 → 메모리 공간의 크기 사전에 정해둘 수 없음
  • 원시 값은 상대적으로 적은 메모리를 소비하지만, 객체는 경우에 따라 크기가 매우 클 수 있음

[객체의 관리 방식]

프로퍼티 키를 인덱스로 사용하는 해시 테이블과 유사

  • V8 JS 엔진에서는 프로퍼티에 접근하기 위해 동적 탐색 대신 히든 클래스 방식 사용

11.2.1 변경 가능한 값

객체(참조) 타입의 값, 즉 객체는 변경 가능한 값

var 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(c1.x === o.x); // true

    깊은 복사: 객체에 중첩되어 있는 객체까지 모두 복사하는 것, 객체에 중첩되어 있는 객체까지 모두 복사해서 원시 값처럼 완전한 복사 만듦 ⇒ 원시 값을 할당한 변수를 다른 변수에 할당하는 것

    • 원본과 복사본은 참조 값이 다른 별개의 객체

      const v = 1;
      // 깊은 복사
      const c1 = v;
      console.log(c1 === v); // true
      
      const o = {x:1};
      // 얕은 복사
      const c2 = o;
      console.log(c2 === o); // true

11.2.2 참조에 의한 전달

여러 개의 식별자가 하나의 객체 공유 가능

var person = {
	name: 'Lee'
};

// 참조 값 복사(얕은 복사)
var copy = person;

  • 객체를 가리키는 변수(원본, person)를 다른 변수(사본, copy)에 할당하면 원본의 참조 값이 복사되어 전달참조에 의한 전달
  • 두 개의 식별자가 하나의 객체를 공유원본 또는 사본 중 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받음
    var person = {
      name: "Lee",
    };
    
    // 참조 값 복사(얕은 복사), copy와 person은 동일한 참조 값 갖는다
    var copy = person;
    
    // copy와 person은 동일한 객체 참조
    console.log(copy === person); // true
    
    // copy를 통해 객체 변경
    copy.name = "Kim";
    
    // person을 통해 객체 변경
    person.address = "Seoul";
    
    // copy와 person은 동일한 객체 가리킴
    // 따라서 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받음
    console.log(person); // {name: 'Kim', address: 'Seoul'}
    console.log(copy); // {name: 'Kim', address: 'Seoul'}
  • === 비교 일치 연산자는 변수에 저장되어 있는 값을 타입 변환하지 않고 비교 → 객체를 할당한 변수를 비교하면 참조 값 비교하고, 원시 값을 할당한 변수 비교하면 원시 값 비교
    var person1 = {
      name: "Lee",
    };
    
    var person2 = {
      name: "Lee",
    };
    
    console.log(person1 === person2); // false
    console.log(person1.name === person2.name); // true
    • person1과 person2는 서로 다른 메모리 주소를 가진 객체

0개의 댓글