본문 바로가기
Javascript/javascript Core

[Javascript 강의]10강. Prototype

by 카리3 2021. 10. 4.

Prototype

프로토 타입은 생성자 함수가 생성되는 시점에 생성된다. 즉 constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.

상속과 프로토타입

자바스크립트는 프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거한다.

//생성자 함수
function Circle(radius){
 this.radius = radius;
 this.getArea = function(){
  return Math.PI * this.radius ** 2;
 }
}

const circle = new Circle(1);
const circle = new Circle(3);

메서드 중복생성

//프로토타입 기반

//생성자함수
function Circle(radius){
 this.radius = radius;
}

//프로토타입에 함수 바인딩
Circle.prototype.getArea = function(){
 return Math.PI * this.radius **2;
}

const circle1 = new Circle(1);
const circle2 = new Circle(3);

상속에 의한 메서드 공유

 

프로토타입 객체

프로토타입 객체는 객체지향 프로그래밍의 근간을 이루는 객체 간 상속을 구현하기 위해 사용된다. 프로토타입은 어떤 객체의 상위 객체의 역할을 하는 객체로서 다른 객체에 공유 프로퍼티(메서드 포함)를 제공한다. 모든 객체는 [[Prototype]]이라는 내부 슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조다. [[Prototype]]에 저장되는 프로토타입은 객체가 생성될 때 객체 생성 방식에 따라 프로토타입이 결정되고 [[Prototype]]에 저장된다. 즉, 객체 리터럴에 의해 생성된 객체의 프로토타입은 Object.prototype이고 생성자 함수에 의해 생성된 객체의 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체다. 모든 객체는 하나의 프로토타입을 갖는다. 그리고 모든 프로토타입은 생성자 함수와 연결되어 있다.

객체의 프로토타입

//prototype get/set
const obj = {};
const parent = {x:1};

obj.__proto__;
obj.__proto__ = parent;

console.log(obj.x); //1


//소스상에서 __proto__ 사용은 피하는것이 좋다.
  const obj1 = {};
  const parent1 = {x:1};

  Object.getPrototypeOf(obj1);//obj1.__proto__
  Object.setPrototypeOf(obj, parent1);//obj1.__proto__=parent1;

  console.log(obj.x);

 

프로토타입 체인

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

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('Kim');

  //인스턴스 메서드
  //프로토타입 메서드 오버라이딩
  //프로토타입 메서드는 프로퍼티 새도잉 된다.
  me.sayHello = function(){
       console.log(`Hey! My name is ${this.name}`);  
  }

  //인스턴스 메서드가 호출된다. 프로토타입 메서드는 인스턴스 메서드에 의해 가려진다.
  me.sayHello(); //Hey! My name is Kim

 

instance of 연산자

  //생성자 함수
  function Person(name){
      this.name = name;
  }
  
  console.log(personObject instanceof Person); //true
  console.log(personObject instanceof Object); //true

 

정적 프로퍼티/메서드

 //정적 메서드
    Person.staticMethod = function () {
        console.log('staticMethod');
    };
    
   //생성자 함수에 추가한 정적 프로퍼티/메서드는 생성자 함수로 참조/호출한다. 
   console.log(Person.staticMethod()); //staticMethod
   
   //정적 프로퍼티/메서드 생성자 함수가 생성한 인스턴스로 참조/호출할 수 없다
   //인스턴스로 참조/호출할 수 있는 프로퍼티/메서드는 프로토타입 체인 상에 존재해야 한다.
   console.log(me.staticMethod()); //Uncaught TypeError: me.staticMethod is not a function

 

프로퍼티 존재확인

  const person = {
    name : 'Lee',
    address : 'Busan'
  };

  //1. in 연산자
  console.log('name' in person); //true
  console.log('age' in person);  //false

  //2. ES6 Reflect.has 메서드
  console.log(Reflect.has(person,'name')); //true
  console.log(Reflect.has(person, 'age')); //false
  
  //3. Object.hasOwnProperty 메서드
  console.log(person.hasOwnProperty('name')); //true
  console.log(person.hasOwnProperty('age')); //false

 

프로퍼티 열거

const sym = Symbol();
  const person = {
    name : 'Kim',
    address : 'Busan',
    [sym]: 20,
    __proto__: {sex:'male'}
  };

  //1. in 연산자
  console.log('name' in person); //true
  console.log('age' in person);  //false

  //2. ES6 Reflect.has 메서드
  console.log(Reflect.has(person,'name')); //true
  console.log(Reflect.has(person, 'age')); //false
  
  //3. Object.hasOwnProperty 메서드
  console.log(person.hasOwnProperty('name')); //true
  console.log(person.hasOwnProperty('age')); //false
  
  //1. in 연산자
  for(const key in person){
      console.log(key+' : '+person[key]);      
  }
  
  //2. Object.keys  Object.values
  console.log(Object.keys(person));
  console.log(Object.values(person));

  //3.Object.entries
  Object.entries(person).forEach( ([key, value]) => console.log(key, value) );