이전 포스트에서 살펴본 것과같이 생성자 함수에 의해 생성된 인스턴스(객체)는 프로토타입의 constructor 프로퍼티에 의해 생성된 함수와 연결된다. 이때 constructor 프로퍼티가 가리키는 생성자 함수는 인스턴스를 생성한 생성자 함수다.
const me = new Person('Lee');
console.log(me.constructor === Person) // true
그러나 생성자함수가 아니라 독립적인 리터럴 표기법에 의해 생성된 객체 생성 방식도 존재하였다. 그리고 이렇게 생성된 객체들도 프로토타입이 존재한다. 그러나 이 경우 constructor프로퍼티가 생성자 함수를 반드시 가리킨다고 볼 수는 없다.
//객체리터럴 -> Object 생성자 함수; Object.prototype
const obj = {};
// 함수 리터럴 -> Function 생성자 함수; Function.prototype
const add = (a, b) => a+b;
//배열리터럴 -> Array 생성자 함수; Array.prototype
const arr = [1,2,3]
//정규표현식 리터럴 -> RegExp 생성자 함수 RegExp.prototype
const regexp = /is/ig;
//객체리터럴의 constructor 확인
console.log(obj.constructor === Object); // true
그럼에도 리터럴로 선언된 다수형태의 객체들이 프로토타입을 가질 수 있는 것은 자바스크립트가 가지고 있는 객체 선언의 내장된(?) 생성자함수들 덕분이다. 그 결과로 다수형태의 객체들은 프로토타입을 가지고 있게 되는 것이다. 즉 큰 틀에서 볼 때 리터럴 표기법으로 생성한 객체도 생성자 함수로 생성한 객체와 본질적인 면에서는 큰 차이가 없는 것이다. 즉 객체는 리터럴 표기법 또는 생성자 함수에 의해 생성되므로 결국 모든 객체는 생성자 함수와 연결되어 있으며, 프로토타입은 생성 시점에서 함께 생성되며 각각의 인스턴스와 결합된다는 점이다. 즉 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.
여기서 다룰 내용은 생성자함수(constructor)와 변수로 선언된 함수표현식(non-constructor)에서 발생되는 constructor의 발생유무이다. 함수선언에 의해 기록된 생성자함수는 런타임 이전에 자바스크립트 엔진이 먼저 실행하기에, 이때 프로토타입도 더불어 생성됨과 함께 생성자함수에 귀속된다.
이런 개념 아래, 사용자가 정의한 생성자 함수나 자바스크립트가 내장하고 있는 생성자 함수(Object, String, Number, Function, Array, RegExp, Date, Promise 등)도 생성자함수가 생성되는 시점에 프로토타입이 생성된다. 다시 말해서 객체가 생성되기 이전에 생성자 함수와 프로토타임은 이미 객채화되어 존재한다는 말이다. 이후 생성자 함수 또는 리터럴 표기법으로 객체를 생성하면 프로토타입은 생성된 객체의 [[Prototype]] 내부 슬롯에 할당되며, 생성자함수에 귀속된 프로토타입을 공유받는다.
자바스크립트는 객체의 프로퍼티(메서드 포함)에 접근하려고 할 때 해당 객체에서 먼저 해당 프로퍼티의 존재를 탐색한다. 그러나 만약 존재하지 않는다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신을 생성한 생성자함수의 프로토타입의 프로퍼티로 나아가 탐색한다. 이러한 프로퍼티의 탐색과정을 프로토타입체인이라고 부르며, 프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘을 단면적으로 보여준다.
배열, 함수 등 모두 사실상 객체라는 것은 우리가 알고 있는 사실이다. 그러기에 모든 객체의 최상의 프로토타입체인에는 Object.prototype 이 존재하며, 모든 객체는 Object.prototype 을 공유(상속) 받는다. 만약 프로토타입체인의 결과 Object.prototype 에서도 요청된 프로퍼티를 탐색할 수 없는 경우에는 undefinded가 반환되는데, 이때 에러가 발생되지는 않는다.
자바스크립트 엔진은 프로토타입 체인을 따라 프로퍼티/메서드를 탐색한다. 즉 객체 간의 상속 관계로 이루어진 프로토타입의 계층적인 구조에서 객체의 프로퍼티를 검색한다.
반면에 식별자(변수명)의 경우에는 스코프 체인을 통해 이뤄진다. 자바스크립트 엔진은 함수의 중첩관계로 이루어진 스코프의 계층적 구조(클로저)에서 식별자를 탐색하는데, 이런 방식을 "스코프 체인"이라고 부르며, 스코프 체인은 식별자 검색을 위한 자바스크립트 엔진의 메커니즘이다.
그러나 프로토타입 체인과 스코프 체인은 별도로 움직이는 것이 아니라, 서로 협력하여 기동하는데, 각각 역할이 다를 뿐이다. 프로토타입체인은 프로퍼티를, 스코프체인은 식별자(변수명)을 탐색해 나아간다.