ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript]프로토타입-2
    JavaScript 2023. 1. 5. 19:02
    728x90

    프로토타입의 생성 시점

    프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성됩니다.

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

    // 함수 정의(constructor)가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
    console.log(Person.prototype); // {constructor: ƒ}
    
    // 생성자 함수
    function Person(name) {
      this.name = name;
    }
    

    위 예제와 같이 전역 컨텍스트가 실행될 때 함수 선언문이 먼저 실행되므로(이 때 프로토타입도 같이 생성된다.) console.log 에 프로토타입이 출력될 수 있다.

    하지만 화살표함수와 같이 생성자함수가 없는 함수는 프로토타입도 미리 생성되지 않는다.

    // 화살표 함수는 non-constructor다.
    const Person = name => {
      this.name = name;
    };
    
    // non-constructor는 프로토타입이 생성되지 않는다.
    console.log(Person.prototype); // undefined
    

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

    객체 리터럴에 의해 생성된 객체의 프로토타입

    객체 리터럴에 의해 생성되는 객체의 프로토타입은 Object.prototype입니다.

    const obj = { x: 1 };
    
    // 객체 리터럴에 의해 생성된 obj 객체는 Object.prototype을 상속받는다.
    console.log(obj.constructor === Object); // true
    console.log(obj.hasOwnProperty('x'));    // true
    

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

    new Object를 통해 obj가 생성될 때 Object.prototype이 연결되어 상속받습니다.

    const obj = new Object();
    obj.x = 1;
    
    // Object 생성자 함수에 의해 생성된 obj 객체는 Object.prototype을 상속받는다.
    console.log(obj.constructor === Object); // true
    console.log(obj.hasOwnProperty('x'));    // true
    

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

    new 생성자 함수에 의해 만들어진 인스턴스는 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
    

    따라서 프로퍼티를 추가 또는 삭제하여 사용해야 한다.

    프로토타입 체인

    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 객체는 Person.prototype을 상속 받았고 Object.prototype도 상속 받았다.

    me 객체는 Person.prototype에 hasOwnProperty가 있는지 확인하고 더 부모인 Object.prototype에 있는지 확인한다. 이를 프로토타입 체인이라고 합니다.

    Object.prototype은 javascript의 포로토타입 체인 종점이라고 합니다.

    • 프로토타입 체인 : 상속과 프로퍼티 검색을 위한 메커니즘
    • 스코프 체인 : 식별자 검색을 위한 메커니즘

    오버라이딩과 프로퍼티 섀도잉

    const Person = (function () {
      // 생성자 함수
      function Person(name) {
        this.name = name;
      }
    
      // 프로토타입 메서드
      Person.prototype.sayHello = function () {
        console.log(`Hi! My name is ${this.name}`);
      };
    
      // 생성자 함수를 반환
      return Person;
    }());
    
    const me = new Person('Lee');
    
    // 인스턴스 메서드
    me.sayHello = function () {
      console.log(`Hey! My name is ${this.name}`);
    };
    
    // 인스턴스 메서드가 호출된다. 프로토타입 메서드는 인스턴스 메서드에 의해 가려진다.
    me.sayHello(); // Hey! My name is Lee
    

    sayHello를 호출할 때 가장 가까이에있는 me의 sayHello를 호출하게 되므로 Hey가 출력되게 됩니다. 즉 상위에있는 sayHello를 하위에서 오버라이딩했다고 할 수 있습니다. 이렇게되면 상위 프로토타입인 Person.prototype에 sayHello는 가려지므로 섀도잉됐다고 합니다.

    // 인스턴스 메서드를 삭제한다.
    delete me.sayHello;
    // 인스턴스에는 sayHello 메서드가 없으므로 프로토타입 메서드가 호출된다.
    me.sayHello(); // Hi! My name is Lee
    

    삭제를했으므로 me에 sayHello가 있나 확인 후 없으므로 상위인 Person.prototype의 sayHello를 호출 합니다.

    프로토타입의 교체

    생성자 함수에 의한 프로토타입의 교체

    const Person = (function () {
      // 생성자 함수
      function Person(name) {
        this.name = name;
      }
    
      // 프로토타입 메서드
      Person.prototype.sayHello = function () {
        console.log(`Hi! My name is ${this.name}`);
      };
    
      // 생성자 함수를 반환
      return Person;
    }());
    
    const me = new Person('Lee');
    
    // 인스턴스 메서드
    me.sayHello = function () {
      console.log(`Hey! My name is ${this.name}`);
    };
    
    // 인스턴스 메서드가 호출된다. 프로토타입 메서드는 인스턴스 메서드에 의해 가려진다.
    me.sayHello(); // Hey! My name is Lee
    

    위 예제에서 Person.prototype에 객체 리터럴을 할당했으므로 constructor 프로퍼티가 없다. 따라서 me 객체의 생성자 함수는 Object.prototype에서 가져오게 된다.

    이처럼 프로토타입을 교체하면 constructor와 프로퍼티 생성자 함수 간의 연결이 파괴되는데 이를 되살리기 위해서는 constructor 프로퍼티를 추가하면 됩니다.

    const Person = (function () {
      function Person(name) {
        this.name = name;
      }
    
      // 생성자 함수의 prototype 프로퍼티를 통해 프로토타입을 교체
      Person.prototype = {
        // constructor 프로퍼티와 생성자 함수 간의 연결을 설정
        constructor: Person,
        sayHello() {
          console.log(`Hi! My name is ${this.name}`);
        }
      };
    
      return Person;
    }());
    
    const me = new Person('Lee');
    
    // constructor 프로퍼티가 생성자 함수를 가리킨다.
    console.log(me.constructor === Person); // true
    console.log(me.constructor === Object); // false
    

    인스턴스에 의한 프로토타입의 교체

    function Person(name) {
      this.name = name;
    }
    
    const me = new Person('Lee');
    const me2 = new Person('Park');
    // 프로토타입으로 교체할 객체
    const parent = {
      sayHello() {
        console.log(`Hi! My name is ${this.name}`);
      }
    };
    
    // ① me 객체의 프로토타입을 parent 객체로 교체한다.
    Object.setPrototypeOf(me, parent);
    // 위 코드는 아래의 코드와 동일하게 동작한다.
    // me.__proto__ = parent;
    
    me.sayHello(); // Hi! My name is Lee
    me2.sayHello(); // Type Error
    

    me객체에 프로토타입을 parent로 교체한거지 Person의 prototype을 교체한게 아니므로 me에만 sayHello가 존재하게 됩니다.

    instanceof 연산자

    프로토타입 체인 상에 존재하면 true로 평가된다.

    // 생성자 함수
    function Person(name) {
      this.name = name;
    }
    
    const me = new Person('Lee');
    
    // Person.prototype이 me 객체의 프로토타입 체인 상에 존재하므로 true로 평가된다.
    console.log(me instanceof Person); // true
    
    // Object.prototype이 me 객체의 프로토타입 체인 상에 존재하므로 true로 평가된다.
    console.log(me instanceof Object); // true
    
    728x90

    'JavaScript' 카테고리의 다른 글

    [JavaScript]프로토타입-3  (0) 2023.01.12
    [JavaScrip] 프로토타입 - 1  (0) 2023.01.03
    [JavaScrip] 함수와 일급 객체  (0) 2022.11.24
    [JavaScript] 생성자 함수에 의한 객체 생성  (0) 2022.11.23
    [백준]1132 : 합(javascript)  (0) 2022.07.25

    댓글

Designed by Tistory.