자바스크립트에서 __proto__ VS. prototype 비교

jangws·2022년 3월 21일
3

Javascript TIL

목록 보기
11/11

SOF - __proto__ VS. prototype

  • __proto__는 메서드 등을 체인을 타고 찾는데 사용되는 실제 객체이다.
  • prototypenew로 인스턴스를 만들 때 __proto__를 생성하는 데 사용하는 객체다.
function Foo() {}
console.log(new Foo().__proto__ === Foo.prototype); // true, 인스턴스의 __proto__와 함수의 prototype은 같다
console.log(new Foo().prototype === Foo.prototype); // false, 인스턴스의 prototype과 함수의 prototype은 다르다.
console.log(new Foo().prototype === undefined); // true, 인스턴스의 prototype은 undefined이다(즉, 없다?).
console.log(new Foo() instanceof Foo); // true
console.log(new Foo() instanceof Object); // true
console.log(new Foo().__proto__.__proto__ === Object.prototype); // true
console.log(Foo.__proto__ === Function.prototype); // true

console.log(new Foo().__proto__); //  Foo.prototype과 동일하다
/* {constructor: ƒ}
	constructor: ƒ Foo
	[[Prototype]]: Object */
console.log(Foo.prototype.constructor); // Foo, 함수 정의 반환
console.log(Foo.prototype.__proto__); // {}, 빈 객체 반환,  함수이므로 root level인 Object.prototype을 가리킨다
  • 함수 정의 코드를 실행하면, 자바스크립트는 해당 함수에 prototype 프로퍼티를 추가한다. 해당 prototype 프로퍼티는 constructor__proto__라는 두 개의 프로퍼티를 가진 객체다.
    - 브라우저에서 콘솔로 찍으면 __proto__는 안 보이고, [[Prototype]]만 보여서 이건 또 뭐냐고 물을 수 있다. 사실 둘은 같은 것이다. 정확히 말하면, __proto__[[Prototype]]에 대하여 브라우저에서 지원하는 getter이다. [[Prototype]]은 private 연결이므로 직접적으로 접근할 수 없다.
  • prototype 프로퍼티는 인스턴스 내에서 사용할 수는 없고, 함수에서만 사용할 수 있다.
  • 대신, 인스턴스는 __proto__프로퍼티를 통해 함수의 prototype 프로퍼티를 참조한다.
  • 그리고 함수 __proto__ 프로퍼티는 더 상위의 Function의 prototype 프로퍼티를 참조한다. 따라서 서로 다른 함수의 __proto__ 프로퍼티들을 비교하면 같음을 확인할 수 있다.
  • 즉, prototype 프로퍼티는 저장되는 실제 객체인 __proto__ 프로퍼티를 위한 청사진일뿐이다. 다른 말로 풀자면, prototype은 생성자 함수(constructor functions)에서 사용되는 것이며, 이러한 정의를 담는 정확한 용어로 "prototypeToInstall"로 했어야 오해가 없었을 것이다.
  • 반면, __proto__의 정의에 잘 맞는 용어는 "installedPrototype"으로 했어야 이해하기 쉬웠을 것이다.

정리해서, 함수를 new 키워드를 사용하여 인스턴스를 만들면 다음과 같은 일이 발생한다.

function SetName(name) {
	this.name = name;
}
const marco = new SetName("Marco");
  1. 빈 새 객체를 만든다.
  2. marco에 __proto__ 프로퍼티를 만들고, 그 __proto__ 프로퍼티가 SetName의 prototype을 가리키게 한다.
  3. 1번에서 만든 새 객체의 context(this)로 SetName.prototype.constructor (= SetName 함수정의)가 실행(execute)되며, 이러한 해당 함수정의에 따라 "Marco" 문자열을 전달받은 'name' 프로퍼티가 새 객체에 추가된다.
  4. const marco에 해당 새 객체(1번에서 만들어진)가 지정되어 반환된다..
  • 결론 : 인스턴스는 __proto__ 프로퍼티만을 제대로 갖고, 클래스와 생성자함수는 추가로 prototype 프로퍼티를 갖는다. 인스턴스의 __proto__ 프로퍼티는 클래스나 생성자함수의 prototype을 가리킨다. (사족을 덧붙이자면, 클래스와 생성자함수의 __proto__ 프로퍼티는 root level의 Function.prototype 프로퍼티를 가리킨다.

추가로 Function과 Object의 프로토타입 관계를 아담과 이브에 빗대어 살펴보자.(SOF - __proto__ VS. constructor.prototype)
Object는 이브이고, Function은 아담이다. 아담(Function)은 그의 갈비뼈(Function.prototype)을 사용하여 이브(Object)를 창조하였다. 그러면 아담(Function)은 누가 창조했는가? - 자바스크립트 언어를 만든 사람! -
따라서 아래와 같은 비교 결과가 모두 참이 된다.

console.log(Object.__proto__ === Function.prototype); // true
console.log(Function.prototype === Function.__proto__); // true, 그 위는 없다.
console.log(Object.__proto__ === Foo.__proto__);  // true, 둘 다 Function.prototype을 참조한다.

예제

class Foo {
    hello() {return '안녕하세요'}
}
class Bar extends Foo{
    #age;
    constructor(){
        super();
        this.name = "마르코";
        this.#age = 11;
    }
    
    getName(){return this.name + " 입니다"}
    get age(){return this.#age }
    static bye() {return '잘가요'}
}
const bar = new Bar();
console.dir(Foo);
console.dir(Bar);
console.dir(new Foo());
console.dir(new Bar());

콘솔결과

0개의 댓글