참고할 페이지 - 유사 배열 객체, 이터러블, 래퍼 객체

원시 값
변경 불가능한 값
- 읽기 전용 (값은 변경이 불가능한 값)
- 불변성 (원시 값을 할당하는 변수는 재할당 이외에 변경할 수 없다.)

원시 값을 할당한 변수가 기억하는 메모리 주소를 통해 메모리 공간에 접근하면 원시 값에 접근할 수 있다. 즉, 원시 값을 할당한 변수는 원시 값 자체를 갖는다.

- 원시 값을 할당한 변수에 새로운 원시 값을 재할당하면 메모리 공간에 저장되어 있는 재할당 이전의 원시 값이 변경되는 것이 아니다.
- 새로운 공간을 확보하고 재할당한 원시 값을 저장한 후, 변수는 새롭게 재할당한 원시 값을 가리킨다.
- 이때 변수가 참조하던 메모리 공간의 주소가 바뀐다.
원시 값은 변경 불가
- 원시 값 자체를 변경할 수 없다는 것이지 변수 값을 변경할 수 없다는 것이 아니다.
- 변수는 재할당을 통해 변수 값을 변경한다.
상수
- 재할당이 금지된 변수
- const는 원시 값을 변경할 수 없다. 단, 변수에 할당한 객체는 변경할 수 있다.
문자열과 불변성
var str = "Hello"; str = "Bye";
- 자바스크립트의 문자열은 원시 타입이며, 변경이 불가능하다.
- 위 예제는 Hello와 Bye 모두 메모리에 존재하고 식별자 str은 문자열 Hello를 가리키고 있다가 Bye를 가리키도록 변경되었을 뿐이다.
- 문자열은 유사 배열 객체이면서 이터러블이므로 배열과 유사하게 각 문자에 접근할 수 있다.
값에 의한 전달

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
- 변수에 원시 값을 갖는 변수를 할당하면 할당한 변수 copy에는 할당되는 변수 score의 원시 값이 복사되어 전달된다.
- 원시 값은 동일하지만 다른 메모리 공간에 저장된 별개의 값이다.
객체
- 객체는 프로퍼티의 개수가 정해져 있지 않고 프로퍼티의 값에도 제약이 없다.
- 동적으로 추가되고 삭제할 수 있다.
- 원시 값과 같이 메모리 공간의 크기를 사전에 정해 둘 수 없다.
- 객체는 복합적인 자료구조이고 관리 방식이 브라우저 제조마다 다를 수 있다.
- 원시 값보다 비용이 많이 든다.
🙂 자바스크립트 객체의 관리 방식

- 객체는 프로퍼티 키를 인덱스로 사용하는 해시 테이블과 유사하다.
- 자바스크립트는 클래스 없이 객체를 생성할 수 있으며 객체가 생성된 이후라도 동적으로 프로퍼티와 메서드를 추가할 수 있다.
- 클래스 기반 객체지향 프로그래밍 언어(자바, C++)는 사전에 정의된 클래스를 기반으로 객체(인스턴스)를 생성하고 생성된 이후에는 프로퍼티를 삭제하거나 추가할 수 없다.
- 자바스크립트는 사용하기 편리하지만 생성과 프로퍼티 접근에 비용이 더 많이 드는 비효율 방식이다.
- V8 자바스크립트 엔진에서는 프로퍼티에 접근하기 위해 동적 탐색 dynamic lookup 대신 히든 클래스 hidden class라는 방식을 사용
- C++ 객체의 프로퍼티에 접근하는 정도의 성능을 보장한다.
- 자바와 같이 고정된 객체 레이아웃(클래스)과 유사하게 동작한다.
변경 가능한 값
- 객체(참조) 타입의 값, 즉 객체는 변경이 가능한 값
- 객체를 할당한 변수가 기억하는 메모리 주소를 통해 메모리 공간에 접근하면 참조값(reference value)에 접근할 수 있다.
- 참조 값은 생선 된 객체가 지정된 메모리 공간의 주소, 그 자체이다.

// 할당이 이뤄지는 시점에 객체 리터널이 해석되고, 그 결과 객체가 생성된다. var person = { name: 'Lee' }; // person 변수에 저장되어 있는 참조 값으로 실제 객체에 접근한다. 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(c1.x === o.x); // true // lodash의 cloneDeep을 사용한 깊은 복사 // "npm install lodash"로 lodash를 설치한 후, Node.js 환경에서 실행 const = require('lodash'); // 깊은 복사 const c2 = _cloneDeep(o); console.log(c2 === o); // false console.log(c2.x === o.x); // false
- 얕은 복사와 깊은 복사로 생성된 객체는 원본과는 다른 객체다. 즉, 원본과 복사본은 참조 값이 다른 별개의 객체이다.
- 위 예제에서 얕은 복사는 객체에 중첩되어 있는 객체의 경우 참조 값을 복사한다.
- 깊은 복사는 객체에 중첩되어 있는 객체까지 모두 복사해서 원시 값처럼 복사본을 만든다.
const v = 1; // "깊은 복사"라고 부르기도 한다. const c1 = v; // pass by value console.log(c1 === v); // true const o = { x: 1 }; // "얕은 복사"라고 부르기도 한다. const c2 = o; // pass by reference console.log(c2 === o); // true
- 원시 값을 할당한 변수에 할당하는 것을 깊은 복사
- 객체를 할당한 변수를 다른 변수에 할당하는 것을 얕은 복사라고 부르는 경우가 있다.
참조에 의한 전달
여러 개의 식별자가 하나의 객체를 공유할 수 있다는 것이 무엇을 의미하는지, 이로 인해 어떤 부작용이 발생하는지 확인해 보기.
var person={ name: 'Lee' }; // 참조 값을 복사(얕은 복사) var copy = person;

- 참조에 의한 전달 : 객체를 가리키는 변수 (원본, person)를 다른 변수 (사본, copy)에 할당하면 원본의 참조 값이 복사되어 전달된다.
- 원본 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); // 1 console.log(person1.name === person2.name); // 2
일치 비교 연산자는 변수에 저장되어 있는 값을 타입 변환하지 않고 비교한다.
- 객체를 할당한 변수는 참조 값을 가지고 있다.
- 원시 값을 할당한 변수는 원시 값 자체를 가지고 있다.
- 1번은 false다.
- person1 변수와 person2 변수가 가리키는 객체는 내용은 같지만 다른 메모리에 저장된 별개의 객체다.
- 즉, person1 변수와 person2 변수의 참조 값은 전혀 다른 값이다.
- 2번은 true다.
- 프로퍼티 값을 참조하는 person1.name과 person2.name은 값으로 평가될 수 있는 표현식이다.
- 두 표현식 모두 원시 값 'Lee'로 평가된다.
'Frontend > JavaScript' 카테고리의 다른 글
클로저 (0) | 2024.04.13 |
---|---|
실행 컨텍스트 (0) | 2024.03.23 |
유사 배열 객체, 이터러블, 래퍼 객체 (0) | 2024.03.13 |
함수 정의 (함수 선언문, 함수 표현식) (0) | 2024.03.07 |
함수 호이스팅 (0) | 2024.03.06 |