하는 일
- 일반 자바스크립트 객체를 하나 만듦.
- 위에서 만든 객체의
[[prototype]]
을 생성자 함수의prototype
과 연결. - 생성자 함수를 주어진 인자로 실행, 1번에서 만든 객체의 this binding 진행.
- 생성자 함수가 원시값이 아닌 무언가를 반환한다면 그게 new 를 사용한 표현식의 최종 결과물. 아니라면 1번에서 만든 객체가 반환값이 됨.
자세한 과정
new
- new의 피연산자의 이름을 가진 친구의 값을 찾아옴. (Evaluation, getValue)
당연하겠지만 일반적인 경우에는 함수-참조 타입-일 테니까 해당 포인터가 가리키는 대상 자체를 가져옵니다. - 피연산자의 argument가 비어 있다면 argList를 빈 배열로 설정.
- 피연산자에게
[[Construct]]
property가 있는지 확인 (IsConstructor)
생성자는 해당 property가 있어야만 합니다. - [[Construct]] 실행.
[[Construct]]
크게 [[ConstructorKind]]가 BASE인 경우와 DERIVED인 경우로 나누어집니다. 보통 생성자는 전부 BASE로 되어 있고, extends 를 사용한 클래스의 생성자는 DERIVED로 되어 있는데요. 일단 이 글에서는 BASE인 경우만을 살펴보겠습니다.
(참고: 15.7.14 Runtime Semantics: ClassDefinitionEvaluation의 16번, 17번 항)
- 생성자의 prototype을 가져옴. (GetPrototypeFromConstructor)
- 일반 객체를 만듦 (OrdinaryObjectCreate)
이 과정에서 위의 prototype을 할당합니다. - execution context stack에 새로운 context를 쌓음. (PrepareForOrdinaryCall)
- 3에서 만든 context의 LexicalEnvironment의 this에 2에서 만든 객체를 bind. (OrdinaryCallBindThis)
- 생성자 함수 내용물 실행. (OrdinaryCallEvaluateBody)
- execution context stack에서 3의 context를 제거
- 3의 context의 LexicalEnvironment의 this binding 을 결과물로 반환 (GetThisBinding)
DERIVED라면 4번을 진행하지 않고 5번을 재귀적으로 진행하면서 가장 위쪽 조상님이 this binding 을 해 줄 것으로 보입니다.
만약 생성자 함수에 반환값이 존재한다면 7번 대신 해당 반환값을 결과물로 반환합니다.
특이사항
- '단항 연산자'로 분류됨.
- 클래스 인스턴스는 new 연산자로만 만들 수 있음.
- 생성자 함수 내부에서
new.target
이 undefined인지 아닌지로 이 함수가 new 연산자를 통해 불렸는지 확인 가능. 이를 이용한다면 일반 함수를 생성자 함수로만 사용할 수 있게끔 강제할 수 있음. Array()
,Error()
,Function()
은 함수로 사용했을 때와 new를 붙여 생성자로 사용했을 때 동작이 똑같음Boolean()
,Number()
,String()
은 함수로 사용했다면 강제로 주어진 값을 원시값으로 바꿔버림. 하지만 생성자로 사용했다면 wrapper object를 반환하여 typeof를 찍었을 때 'object'가 나옴.Symbol()
,BigInt()
는 함수로만 사용할 수 있음.Proxy
,Map
은 생성자로만 사용할 수 있음.const list = new Array;
처럼()
없이 사용했을 경우 자동적으로 생성자의 인자는 비어 있는 것으로 설정됨 (argList가 []).
참고 자료
new - JavaScript | MDN
ECMAScript 2025 Language Specification - 13.3.5 The new operator
ECMAScript 2025 Language Specification - 7.3.14 Construct
ECMAScript 2025 Language Specification - 10.2.2 [[Construct]]