19.4 리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입
리터럴이란? 리터럴은 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법을 말한다. 자바스크립트 엔진은 코드가 실행되는 시점인 런타임에 리터럴을 평가해 값을 생성한다. 즉 리터럴은 값을 생성하기 위해 미리 약속한 표기법이라고 할 수 있다.
- 리터럴 표기법(객체 리터럴, 함수 리터럴, 배열 리터럴, 정규 표현식 리터럴 등) 에 의해 생성된 객체도 상속을 위해 프로토타입이 필요하다. 그 이유로 가상적인 생성자 함수를 갖는다.
- 프로토타입은 생성자 함수와 더불어 생성되며 prototype, constructor 프로퍼티에 의해 연결되어 있다. 즉 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.
- 리터럴 표기법에 의해 생성된 객체는 생성자 함수에 의해 생성된 객체는 아니지만 큰 틀에서 생각해 보면 본질적으로 큰 차이가 없다.
- 생성 과정과 스코프, 클로저 등의 차이가 있지만 결국 함수로서 동일한 특성을 갖는다.
- 프로토타입의 constructor 프로퍼티를 통해 연결되어 있는 생성자 함수를 리터럴 표기법으로 생성한 객체를 생성한 생성자 함수로 생각해도 괜찮다.
리터럴 표기법 | 생성자 함수 | 프로토 타입 |
---|
객체 리터럴 | Object | Object.prototype |
함수 리터럴 | Function | Function.prototype |
배열 리터럴 | Array | Array.prototype |
정규 표현식 리터럴 | RegExp | RegExp.prototype |
19.5 프로토타입의 생성 시점
- 프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다. 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재하기 때문이다.
- 생성자 함수는 사용자 정의 생성자 함수와 빌트인 생성자 함수로 구분할 수 있다.
19.5.1 사용자 정의 생성자 함수와 프로토타입 생성 시점
- 내부 메서드를 갖는 함수 객체, 화살표 함수나 ES6의 메서드 축약 표현으로 정의하지 않고 일반 함수 (함수 선언문, 함수 표현식)으로 정의한 함수 객체는 new 연산자와 함께 생성자 함수로 호출할 수 있다. (17.2.5 참조)
- c생성자 함수로 호출할 수 있는 함수, 즉 constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
constructor
console.log(Person.prototype);
function Person(name) {
this.name = name;
}
non-constructor
const Person - name => {
this.name = name;
};
console.log(Person.prototype);
- 함수 선언문은 런타임 이전에 자바스크립트 엔진에 의해 먼저 실행된다. 따라서 함수 선언문으로 정의된 Person 생성자 함수는 어떤 코드보다 먼저 평가되어 함수 객체가 된다. 이때 프로토 타입도 함께 생성된다.
19.5.2 빌트인 생성자 함수와 프로토타입 생성 시점
- 일반 함수와 마찬가지로 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다. 모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성된다. 생성된 프로토타입은 빌트인 생성자 함수의 prototype 프로퍼티에 바인딩된다.
- 생성자 함수 또는 리터럴 표기법으로 객체를 생성하면 프로토타입은 생성된 객체의 [[Prototype]] 내부 슬롯에 할당된다.
19.6 객체 생성 방식과 프로토타입의 결정
객체의 다양한 생성 방법
- 객체 리터럴
- Object 생성자 함수
- 생성자 함수
- Object.create 메서드
- 클래스(ES6)
- 각 세부적인 객체 생성 방식에 차이가 있지만 공통점은 OrdinaryObjectCreate 에 의해 생성된다는 것이다.
19.6.1 객체 리터럴에 의해 생성된 객체의 프로토 타입
const obj = { x : 1 };
console.log(obj.constructor === Object);
console.log(obj.hasOwnProperty('x'));
19.6.2 Object 생성자 함수에 의해 생성된 객체의 프로토타입
const obj = new Object();
obj.x = 1;
console.log(obj.constructor == Object);
console.log(obj.hasOwnProperty('x'));
- 객체 리터럴과 Object 생성자 함수에 의한 객체 생성 방식의 차이는 프로퍼티를 추가하는 방식에 있다. 객체 리터럴 방식은 객체 리터럴 내부에 프로퍼티를 추가하지만 Object 생성자 함수 방식은 일단 빈 객체를 생성한 이후 프로퍼티를 추가해야 한다.
19.6.3 생성자 함수에 의해 생성된 객체의 프로토타입
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
- 19.6.2 의 경우는 Object 생성자 함수와 더불어 생성된 프로토타입 Object.prototype 이 다양한 빌트인 메서드 (hasOwnProperty.. etc) 를 갖고 있디.
- But, 사용자 정의 생성자 함수 Person과 더불어 생성된 프로토타입 Person.prototype의 프로퍼티는 constructor 뿐이다.
프로토타입 Person.prototype에 프로퍼티를 추가하여 하위 객체가 상속받을 수 있게 하는 방법
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function () {
console.log(`Hi~ My name is ${this.name}`};
};
const me = new Person('Lee');
const you = new Person('Kim');
me.sayHello();
you.sayHello();
- Person 생성자 함수를 통해 생성된 모든 객체는 프로토타입에 추가된 sayHello 메서드를 상속받아 사용할 수 있다.
🌳 느낀점
- 프로토 타입에 메서드를 추가해서 상속받는 방법을 개념도 모른 체 사용했던 적이 있었다. 지금 개념을 확실하게 집고 넘어가니 이제야 전체적인 시나리오가 그려진다. 역시 기본이 중요하다. 🧚♀️
위 글은 위키북스의 모던 자바스크립트 Deep Dive 를 읽고 정리한 내용입니다.