ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Javascript]Prototype (2) 프로토타입 체인
    사부작사부작/Javascript 2022. 3. 15. 20:09

    #모던자바스크립트_딥다이브 스터디를 진행하면서 정리한 내용입니다.

    프로토타입의 생성 시점

    prototype과 생성자 함수는 단독으로 존재할 수 없기 때문에,  prototype은 생성자 함수가 생성되는 시점에 생성된다. 

     

    1. 사용자 정의 생성자 함수와 프로토타입 생성 시점

    일반 함수(함수 선언문, 함수 표현식)로 정의한 함수 객체는 new 연산자와 함께 생성자 함수로서 호출할 수 있다.

    생성자 함수로서 호출할 수 있는 함수, 즉 constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 prototype 프로퍼티도 함께 생성된다.

    // 함수 Person이 평가될 때 자동으로 ptototype도 함께 생성됨
    console.log(Person.prototype); // {constructor: ƒ}
    
    // 생성자 함수
    function Person(name) {
      this.name = name;
    }

     

    Person.prototype을 자세히 보자

    생성된 prototype은  Person의 prototype 프로퍼티에 바인딩 되고 prototype 프로퍼티는 객체이고, 모든 객체는[[prototype]]을 가지므로 prototype 자체도[[prototype]]을 가진다. 이 [[prototype]]은 Object.prototype이다. 따라사 사용자 정의 생성자 함수는 자신이 평가되어 함수 객체로 생성되는 시점에서 prototype 프로퍼티를 가지게 되고 이 프로퍼티의 [[prototype]]은 언제나 Object.prototype이므로 Object의 메서드를 사용할 수 있게 되는 것이다.

     

     

    2. 빌트인 생성자 함수와 프로토타입 생성 시점

    빌트인 생성자 함수도 일반 함수와 마찬가지로 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다. 모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성된다. 즉, 객체가 생성되기 이전에 생성자 함수와 프로토타입은 이미 객체화 되어 있다. 이후 생성자 함수 또는 리터럴 표기법으로 객체를 생성하면 프로토타입은 생성된 객체의 [[prototype]] 내부 슬롯에 할당된다. 

     

     

    객체 생성 방식과 프로토타입의 결정

     

    1. 생성자 함수에 의해 생성된 객체의 프로토타입

    new 연산자와 함께 생성자 함수를 호출하여 인스턴스를 생성하면 추상 연산 OrdinaryObjectCreate가 호출된다. 이때, OrdinaryObjectCreate에 전달되는 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩되어 있던 객체이다. 즉, 생성자 함수에 의해 생성되는 객체의 [[prototype]]은 생성자 함수의 prototype프로퍼티에 바인딩되어 있는 객체이다.

    function Person(name) {
      this.name = name;
    }
    
    const me = new Person('Lee');

    위 처럼 프로포타입의 별다른 정의 없사용자 정의 생성자 함수와 함께 생성된 prototype의 프로퍼티는 constructor뿐이다.

     

    프로토타입은 객체이므로 프로퍼티를 추가/삭제할 수 있다. 그리고 이 변경 사항은 프로토타입 체인에 즉각 반영된다.

    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();  // Hi! My name is Lee
    you.sayHello(); // Hi! My name is Kim

     

    2. 객체 리터럴에 의해 생성된 객체의 프로토타입과 Object 생성자 함수에 의해 생성된 객체의 프로토타입

    객체 리터럴에 의해 생성된 객체의 프로토타입과 Object 생성자 함수에 의해 생성된 객체의 프로토타입은 결과적으로는 같은 구조를 가진다. 다만, 프로퍼티 추가 방식에는 차이가 있다. 객체 리터럴 방식은 객체 리터럴 내부에 프로퍼티를 추가하지만, Object 생성자 함수 방식은 일단 빈 객체를 생성한 이후 프로퍼티를 추가해야 한다.

     

     

    프로토타입 체인

    function Person(name) {
      this.name = name;
    }
    
    // 프로토타입 메서드
    Person.prototype.sayHello = function () {
      console.log(`Hi! My name is ${this.name}`);
    };
    
    const me = new Person('Lee');
    
    // hasOwnProperty는 Object.prototype의 메서드다.
    console.log(me.hasOwnProperty('name')); // true

    Person 생성자 함수에 의해 생성된 me 객체는 Object.prototype의 메서드인 hasOwnProperty를 호출할 수 있다. 이것은 me 객체가 Person.prototype뿐만 아니라 Object.prototype도 상속받았다는 것을 의미한다.

    Object.getPrototypeOf(me) === Person.prototype; // -> true
    Object.getPrototypeOf(Person.prototype) === Object.prototype; // -> true

    자바스크립트는 객체의 프로퍼티와 메서드에 접근하려고 할 때  해당 객체에 접근하려는 프로퍼티가 없다면 [[prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인이라고 한다. 프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 매커니즘이다.

    // hasOwnProperty는 Object.prototype의 메서드다.
    // me 객체는 프로토타입 체인을 따라 hasOwnProperty 메서드를 검색하여 사용한다.
    me.hasOwnProperty('name'); // -> true

    프로토타입 체인의 최상위에 위치하는 객체는 언제나 Object.prototype이다. 따라서 모든 객체는 Object.prototype을 상속받는다. Object.prototype을 프로토타입 체인의 종점이라고 한다. 따라서 Object.prototype의 [[prototype]]의 내부 슬롯 값은 null이다.

     

    만약에 검색하는 프로퍼티가 프로토타입 종점에도 없는 경우 에러가 발생하지 않고 undefined를 반환하는 것에 주의하자.

    console.log(me.foo); // undefined
    const me = {
     name:"won"
    };
     
    function check = () => {
     console.log(me.hasOwnProperty('name'));
    }
    
    check();

    위 코드의 실행 수넛를 보면, 먼저 스코프 체인에서 me식별자를 검색한다. me 식별자는 전역에서 선언되었으므로 전역 스코프에서 검색된다. me 식별자를 검색한 다음, me 객체의 프로토타입 체인에서 hasOwnProperty 메서드를 검색한다.

    따라서 스코프 체인과 프로토타입 체인은 서로 연관없이 별도로 동작하는 것이 아니라, 서로 협력하여 식별자와 프로퍼티를 검색하는 데 사용된다.

    댓글

Designed by Tistory.