모던 자바스크립트 Deep Dive (3)
📖 정리
- 이 글은 '모던 자바스크립트 Deep Dive'를 읽으면서 새롭게 알게된 내용을 정리하기 위해 쓴 글 입니다.
13장 스코프
14장 전역 변수의 문제점
-
변수는 생성되고 소멸되는 생명 주기가 있는데, 전역 변수의 생명 주기는 애플리케이션의 생명 주기와 같다.
-
지역 변수의 생명 주기는 함수의 생명 주기와 일치한다.
-
변수의 생명 주기는 메모리 공간이 확보된 시점부터 메모리 공간이 해제되어 가용 메모리 풀에 반환되는 시점까지다.
-
변수는 자신이 등록된 스코프가 소멸(메모리 해제)될 때까지 유효하다.
-
전역 변수의 문제점
- 모든 코드가 전역 변수를 참조하고 변경할 수 있는 암묵적 결합을 허용한다.
- 생명 주기가 길다. 이로 인해서 메모리 리소스가 낭비되고, 변수 이름이 중복될 가능성이 있다.
- 스코프 체인 상에서 종점에 있기 때문에 전역 변수의 검색 속도가 가장 느리다.
- 파일이 분리되어 있다고 해도 하나의 전역 스코프를 공유하기 때문에 네임스페이스가 오염될 수 있다.
-
변수의 스코프는 좁을수록 좋다.
15장 let, const 키워드와 블록 레벨 스코프
-
var의 문제점
- 변수 중복 선언 허용
- 함수 레벨 스코프: 오직 함수의 코드 블록만 지역 스코프로 인정한다.
- 변수 호이스팅
-
let
- 변수 중복 선언 금지
- 블록 레벨 스코프: if문, for문, while문, try/catch문 등 포함
- 변수 호이스팅이 발생하지 않는 것 처럼 보임
- 이는 선언 단계와 초기화 단계가 분리되있기 때문이다.
- 선언 단계: 자바스크립트 엔진에 변수의 존재를 알린다.
- 초기화 단계: undefined로 변수를 초기화한다.
- 선언 단계는 런타임 전에 이루어진다.
- let ~ 문을 만나는 순간에 초기화가 된다.
- 이 사이 구간을 일시적 사각지대라고 한다.
- let 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다.
-
const
- const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 한다.
- 재할당 금지
- 객체를 할당한 경우 값을 변경할 수 있다. 이는 객체의 특성 때문에 그렇다.
- const 키워드는 재할당을 금지할 뿐 불변을 의미하지는 않는다.
16장 프로퍼티 어트리뷰트
-
**내부 슬롯과 내부 메서드는 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티와 의사 메서드이다. **
-
개발자가 직접 접근할 수 있도록 외부로 공개된 객체의 프로퍼티는 아니다. 단 일부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단을 제공하기는 한다.(예: __proto__)
-
자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다.
- 프로퍼티의 상태란 아래의 4가지를 말한다.
- value: 프로퍼티의 값
- writable: 값의 갱신 가능 여부
- enumerable: 열거 가능 여부
- configurable: 재정의 가능 여부
- 프로퍼티의 상태란 아래의 4가지를 말한다.
-
Object.getOwnPropertyDescriptor 메서드는 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환한다.
-
데이터 프로퍼티
- 키와 값으로 구성된 일반적인 프로퍼티다. 지금까지 살펴본 모든 프로퍼티는 데이터 프로퍼티이다.
- [[Value]], [[Writable]], [[Enumerable]], [[Configurable]] 이 있다.
-
접근자 프로퍼티
- 자체적으로는 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티이다.
- [[Get]], [[Set]], [[Enumerable]], [[Configurable]] 이 있다.
- 접근자 프로퍼티는 자체적으로 값을 가지지 않으며 다만 데이터 프로퍼티** 값을 읽거나 저장할 때 관여**할 뿐이다.
-
객체 변경 방지
- Object.preventExtensions 메서드
- 객체의 확장을 금지한다. 프로퍼티 추가를 금지하는 것이다.
- 객체 밀봉
- Object.seal 메서드를 통해 할 수 있다.
- 밀봉된 객체는 읽기와 쓰기만 가능하다.
- Object.isSealed 메서드로 밀봉 여부를 확인 가능하다.
- 객체 동결
- Object.freeze 메서드를 통해 할 수 있다.
- 동결된 객체는 읽기만 가능하다.
- 직속 프로퍼티만 변경이 방지되고 중첩 객체까지는 영향을 주지 못한다.
- 재귀적으로 Object.freeze를 통해서 중첩 객체까지 동결할 수 있다.
- Object.preventExtensions 메서드
17장 생성자 함수에 의한 객체 생성
-
Object 생성자 함수를 호출하면 빈 객체를 생성해서 반환한다.
-
생성자 함수란 new 연산자와 함께 호출하여 객체(인스턴스)를 생성하는 함수를 말한다.
-
생성자 함수의 역할은 프로퍼티 구조가 동일한 인스턴스를 생성하기 위한 템플릿(클래스)으로서 동작하여 인스턴스를 생성하는 것과 생성된 인스턴스를 초기화(인스턴스 프로퍼티 추가 및 초기값 할당)하는 것이다.
- 초기화하는 것은 옵션이다.
-
자바스크립트 엔진은 다음과 같은 과정을 거쳐 암묵적으로 인스턴스를 생성하고 인스턴스를 초기화한 후 암묵적으로 인스턴스를 반환한다.
- 인스턴스 생성과 this 바인딩
- 암묵적으로 빈 객체가 생성되고 이 객체가 바로 생성자 함수가 생성한 인스턴스다.
- 그리고 암묵적으로 생성된 빈 객체, 즉 인스턴스는 this에 바인딩된다.
- 인스턴스 초기화
- 생성자 함수에 기술되어 있는 코드가 한 줄씩 실행되어 this에 바인딩되어 있는 인스턴스로 초기화한다.
- 인스턴스 반환
- 생성자 함수 내부에서 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this를 암묵적으로 반환한다.
- 만약 명시적으로 다른 객체를 반환하면 this가 반환되지 못하고 return 문에 명시한 객체가 반환된다.
- 하지만 명시적으로 원시 값을 반환하면 원시 값 반환은 무시되고 암묵적으로 this가 반환된다.
- 인스턴스 생성과 this 바인딩
-
함수는 객체이지만 일반 객체와 다르다. 일반 객체는 호출할 수 없지만 함수는 호출할 수 있다.
- 함수 객체만을 위한 [[Environment]], [[FormalParameters]] 등의 내부 슬롯과 [[Call]], [[Construct]] 같은 내부 메서드를 추가로 가지고 있다.
- 일반 함수로 호출되면 함수 객체의 내부 메서드 **[[Call]]**이 호출되고, new 연산자와 함께 생성자 함수로서 호출되면 내부 메서드 **[[Construct]]**가 호출된다.
-
함수 객체가 [[Construct]]를 갖는 것은 아니다. 함수 객체는 constructor일 수도 있고 non-constructor일 수도 있다.
-
constructor: 함수 선언문, 함수 표현식, 클래스
-
non-constructor: 메서드(ES6 메서드 축약 표현), 화살표 함수
-
함수가 어디에 할당되어 있는지에 따라 메서드인지를 판단하는 것이 아니라 함수 정의 방식에 따라 constructor와 non-constructor를 구분한다.
-
new.target
- new.target은 ES6에서 지원하는 기능으로 this와 유사하게 constructor인 모든 함수 내부에서 암묵적인 지역 변수와 같이 사용되어 메타 프로퍼티라 부른다.
- 함수 내부에서 new.target을 사용하면 new 연산자와 함께 생성자 함수로서 호출되었는지 확인할 수 있다.
- new 연산자와 함께 생성자 함수로 호출되면 함수 내부의 new.target은 함수 자신을 가리킨다.
- 일반 함수로 호출된 함수 내부의 new.target은 undefined이다.
18장 함수와 일급 객체
-
다음과 같은 조건을 만족하는 객체를 일급 객체라 한다.
- 무명의 리터럴로 생성할 수 있다. 즉 런타임에 생성 가능하다.
- 변수나 자료구조에 저장할 수 있다.
- 함수의 매개변수에 전달할 수 있다.
- 함수의 반환값으로 사용할 수 있다.
-
함수가 일급 객체라는 것은 함수를 객체와 동일하게 사용할 수 있다는 의미이다.
-
함수 객체의 데이터 프로퍼티에는 다음과 같은 것들이 있다.
- arguments
- 함수 객체의 arguments 프로퍼티 값은 arguments 객체다.
- 함수 호출시 전달된 인수들의 정보를 담고 있는 순회 가능한 유사 배열 객체이며, 함수 내부에서 지역 변수처럼 사용된다.
- 함수를 정의할 때 선언한 매개변수는 함수 몸체 내부에서 변수와 동일하게 취급된다.
- 몸체 내에서 암묵적으로 매개변수가 선언되고 undefined로 초기화 된 후 이후 인수가 할당된다.
- 모든 인수는 암묵적으로 arguments 객체의 프로퍼티로 보관된다.
- arguments 객체는 인수를 프로퍼티 값으로 소유하며 프로퍼티 키는 인수의 순서를 나타낸다.
- arguments 객체의 callee 프로퍼티는 호출되어 arguments 객체를 생성한 함수, 즉 함수 자신을 가리킨다.
- arguments 객체의 length 프로퍼티는 인수의 개수를 나타낸다.
- caller
- 비표준 프로퍼티이다. 함수 자신을 호출한 함수를 가리킨다.
- length
- 함수를 정의할 때 선언한 매개변수의 개수를 나타낸다.
- name
- 함수 이름을 나타낸다.
- ES5와 ES6 에서 동작을 달리한다.
- ES5에서 익명함수 표현식의 경우 name 프로퍼티는 빈 문자열이지만, ES6에서는 함수 객체를 가리키는 식별자를 값으로 가진다.
- prototype 프로퍼티
- constructor만이 소유하는 프로퍼티이다.
- 함수가 객체를 생성하는 생성자 함수로 호출될 때 생성자 함수가 생성할 인스턴스의 프로토타입 객체를 가리킨다.
- arguments