프론트엔드 개발자의 기록 공간

[JavaScript DeepDive] 10~11장 본문

모던 자바스크립트 Deep Dive

[JavaScript DeepDive] 10~11장

[리우] 2022. 1. 27. 18:04

📖 학습 목차

  • 10장_객체 리터럴
  • 11장_원시 값과 객체의 비교

 

✅ 객체 리터럴

✍ 객체 리터럴에 의한 객체 생성

c++나 자바 같은 클래스 기반 객체지향 언어는 클래스를 사전에 정의하고 필요한 시점에 new 연산자와 함께 생성자를 호출하여 인스턴스를 생성하는 방식으로 객체를 생성한다.

 

자바스크립트는 프로토타입 기반 객체지향 언어로서 클래스 기반 객체지향 언어와는 달리 다양한 객체 생성 방법을 지원한다.

  • 객체 리터럴 ( {} )
  • Object 생성자 함수
  • 생성자 함수
  • Object.create 메서드
  • 클래스(ES6)

 

var, function과 같은 예약어를 프로퍼티 키로 사용해도 에러가 발생하지 않는다. 하지만 예상치 못한 에러가 발생할 여지가 있으므로 권장하지 않는다.

var foo = {
  //프로퍼티들
  //프로퍼티 키 : 프로퍼티 값
  var: '',
  function: ''
};

console.log(foo); // {var: "", function: ""}

 

✍ 메서드

자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값으로 사용할 수 있다.

자바스크립트 함수는 일급 객체이다. 따라서 프로퍼티 값으로 사용할 수 있다.

프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 메서드라 부른다. 즉, 메서드는 객체에 묶여 있는 함수를 의미한다.

var circle = {
  radius: 5; // 프로퍼티
  
  getDiameter: function () { // 메서드
    return 2 * this.radius;
  }

 

✅ 원시 값과 객체의 비교

  • 원시 값은 변경 불가능한 값이다. 객체(참조) 값은 변경 가능한 값이다.
  • 원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장된다. => 메모리의 stack 영역에 실제 값이 존재, 이에 비해 객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다. => 메모리의 stack 영역에 heap의 참조 값이 저장되고 heap 영역에 객체 실제 값 존재

 

✍ 문자열과 불변성

자바스크립트는 개발자의 편의를 위해 원시 타입인 문자열 타입을 제고한다. 문자열은 원시 타입이며, 변경 불가능하다.

문자열은 유사 배열 객체이면서 이터러블이므로 배열과 유사하게 각 문자에 접근할 수 있다.

var str = "string";
// 문자열은 유사 배열이므로 배열과 유사하게 인덱스 사용해서 접근 가능
console.log(str[0]);
// 원시 값인 문자열이 객체처럼 동작
consolel.log(str.length); // 6
consolel.log(str.toUpperCase()); // STRING
원시 값을 객체처럼 사용하면 원시값을 감싸는 래퍼 객체로 자동 변환된다. 이는 21.3절 "원시 값과 래퍼 객체"에서 다룰 예정이다.

 

✍ 변수 메모리 관리

[JavaScript DeepDive] 4~6장에서도 언급했지만 변수가 참조하던 값을 바꾸더라도 원시 값은 변경이 불가능한 값이기 때문에 이전 값을 덮어쓰는 게 아니라 새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장한 후, 변수는 새롭게 재할당한 원시 값을 가리킨다. 이때 참조하던 메모리 공간의 주소가 바뀐다.

 

중요!

그럼 만약 다음과 같은 코드일 때, JS 메모리 구조는 어떻게 될까?

var score = 80;
var copy = score;
console.log(score === copy) // true

score 변수에 80할당하고 copy에 score 할당할 때 메모리는 어떻게 할당될까?


1. 새로운 메모리를 할당하고 80 값이 복사되고 그 메모리 주소를 copy가 참조한다.
2. copy도 score와 같은 메모리 주소를 참조한다.

결과는 알 수 없다. ECMAScript 사양에는 변수를 통해 메모리를 어떻게 관리해야 하는지 명확하게 정의가 되어 있지 않기 때문이다. 그래서 자바스크립트 엔진을 구현하는 제조사에 따라 다를 수 있다.
하지만 다른 언어(c, java, python)는 2번과 같은 방식을 사용한다.

✍ 객체

객체는 프로퍼티의 개수가 정해져 있지 않으며, 동적으로 추가되고 삭제할 수 있다. 따라서 메모리 공간의 크기를 사전에 정해 둘 수 없다. 객체를 생성하고 프로퍼티에 접근하는 것은 원시 값과 비교할 때 비용이 많이 든다. 따라서 객체는 원시 값과는 다른 방식으로 동작하도록 설계되어 있다.

 

자바스크립트 객체는 프로퍼티 키를 인덱스로 사용하는 해시 테이블과 유사하지만 높은 성능을 위해 일반적인 해시 테이블 보다 나은 방법으로 객체를 구현한다.

 

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

객체를 할당한 변수가 기억하는 메모리 주소를 통해 메모리 공간에 접근하면 참조 값에 접근할 수 있다. 참조 값은 생성된 객체가 저장된 메모리 공간의 주소, 그 자체다.

 

객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다. 즉, 재할당 없이 프로퍼티를 동적으로 추가할 수도 있고 프로퍼티 값을 갱신할 수도 있으면 프로퍼티 자체를 삭제할 수도 있다.

객체는 변경 가능한 값이다.

앞에서 언급했듯이 객체를 생성하고 관리하는 방식은 매우 복잡하며 비용이 많이 든다. 원시 값처럼 객체를 변경할 때마다 메모리를 재 할당을 통해 변경한다면 명확하고 신뢰성은 확보되겠지만 객체가 매우 크고 일정하지 않기 때문에 비용이 많이 든다. 즉, 메모리의 효율적 소비가 어렵고 성능이 나빠진다.

 

따라서 메모리를 효율적으로 사용하기 위해, 객체는 변경 가능한 값으로 설계되어 있다.

하지만 여러 개의 식별자가 하나의 객체를 공유하기 때문에 한 쪽에서 변화가 일어나면 다른 식별자의 값도 바뀐다는 단점이 있다.

 

var person = {
  name: 'Lee'
};
// 참조 값을 복사(얕은 복사)
var copy = person;

참조에 의한 전달

위 그림처럼 원본 person을 사본 copy에 할당하면 동일한 참조 값을 갖는다. 다시 말해 둘 다 동일한 객체를 가리킨다. 이것은 두 개의 식별자가 하나의 객체를 공유한다는 것을 의미한다.

따라서 person, copy 중 어느 한쪽에서 객체를 변경하면 서로 영향을 주고받는다.

이를 피하기 위해서는 깊은 복사를 이용해 별개의 객체로 복사해서 사용해야 한다. (자세히 알아보기)

 

결국 "값에 의한 전달"과 "참조에 의한 전달"은 식별자가 기억하는 메모리 공간에 저장되어 있는 값을 복사해서 전달한다는 면에서는 동일하다. 다만 식별자가 기억하는 메모리 공간, 즉 변수에 저장되어 있는 값이 원시 값이냐 참조 값이냐의 차이만 있을 뿐이다. 따라서 자바스크립트에는 "참조에 의한 전달"은 존재하지 않고 "값에 의한 전달"만이 존재한다고 말할 수 있다. 

 

앞에서 언급했듯이 자바스크립트의 이 같은 동작 방식을 설명하는 용어가 존재하지 않는다. 그래서 "공유에 의한 전달"이라고 표현하기도 한다.

 

👨‍💻 10~11장을 공부하면서 원시 타입과 객체 타입에 대해 명확하게 알 수 있었고, 다른 언어와 다른 JS의 객체 특징에 대해서도 알 수 있었다. JS 메모리 구조나 내부 동작에 대해서 항상 궁금했는데 이번 파트에서 학습할 수 있어서 매우 좋았다. 이 장은 꼼꼼히 학습하고 이해하는 것을 추천드린다.

728x90

'모던 자바스크립트 Deep Dive' 카테고리의 다른 글

[JavaScript DeepDive] 13~15장  (0) 2022.02.10
[JavaScript DeepDive] 12장_함수  (0) 2022.02.09
[JavaScript DeepDive] 7~9장  (0) 2022.01.25
[JavaScript DeepDive] 4~6장  (0) 2022.01.24
[JavaScript DeepDive] 1~3장  (0) 2022.01.20
Comments