프로토타입

jeongjwon·2023년 3월 16일
0

SEB FE

목록 보기
21/56

📌 상속과 프로토타입

✅ 상속이란?
객체 지향 프로그래밍의 개념으로 어떤 객체의 프로퍼티 (속성) 또는 메서드를 다른 객체가 그대로 사용할 수 있는 것

class Student {
  constructor(name, department){
    this.name = name;
    this.department = department;
  }
  study(){ 
    consoel.log(`${this,name}이 도서관에서 공부 중입니다.`);
  }
  
}
let jiwon = new Student('정지원', 'software');

Student.prototype.constructor === Student; //true
Student.prototype === jiwon.__proto__; //true
Student.prototype.study === jiwon.study; //true

Student.prototype 이라는 Object 가 존재하고,
클래스 내부에서 study 함수를 생성하였기 떄문에 자동으로 prototype 이 등록이 된다.
Student 생성자함수를 통해 생성된 jiwon 도 Object 에 포함되는 함수(study)를 사용할 수 있다.


//생성자 함수
class Circle {
  constructor(radius){
    this.radius = radius;
    this.getPerimeter = function(){
      return this.radius * 2 * Math.PI;
    };
  }
}
//인스턴스 생성
const circle1 = new Circle(1);
const circle2 = new Circle(2);

//Circle 생성자 함수는 인스턴스를 생성할 때 마다
//동일한 동작을 하는 getPerimeter 메서드를 중복으로 생성하여 모든 인스턴스가 중복 소유한다.
console.log(circle1.getPerimeter === circle2.getPerimeter);//false

👉🏻 이렇게 중복으로 생성하고 모든 인스턴스가 중복으로 소유하는 getPerimeter 메서드는 불필요한 메모리 낭비를 시킨다. 따라서, 동일하게 사용되는 메서드는 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 필요하다.

💡 프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거한다.

//생성자 함수
class Circle {
  constructor(radius){
    this.radius = radius;
  }
}
//Circle 생성자 함수가 생성한 모든 인스턴스가 
//getPerimeter 메서드를 공유해서 사용할 수 있도록 프로토타입에 추가한다.
//프로토타입은 Circle 생성자 함수의 prototype 프로퍼티에 바인딩되어 있다.
Circle.prototype.getPerimeter = function(){
	return this.radius * 2 * Math.PI;
};
const circle1 = new Circle(1);
const circle2 = new Circle(2);

//Circle 생성자 함수가 생성한 모든 인스턴스는 
//부모 객체의 역할을 하는 프로토타입 Circle.prototype 으로부터 getPerimeter 메서드를 상속받는다.
//즉, Circle 생성자 함수가 생성하는 모든 인스턴스는 하나의 getPerimeter 메서드를 공유한다.
console.log(circle1.getPerimeter === circle2.getPerimeter); //true 
  • 생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입(부모 객체 Circle.prototype) 이 가지고 있는 속성과 메소드를 상속받는다.
  • getPerimeter 메서드는 하나만 생성되어 Circle.prototype의 메서드로 할당되어 모든 인스턴스는 이 메서드 또한 *상속8받아 사용할 수 있다.
  • radius 프로퍼티만 개별적으로 소유하고 내용이 동일한 getPerimeter 메서드는 상속을 통해 공유하여 사용할 수 있다.

이와 같은 상속은 코드의 재사용함으로써 메모리를 아낄 수 있고, 프로토타입 객체를 공유한다는 점에서 유용하다.

📌 프로토타입 객체

✅ 프로토타입
어떤 객체의 부모역할을 하는 객체로서 다른 객체에게 공유 프로퍼티를 제공

💡 모든 객체는 자신의 부모 역할을 담당하는 객체(프로토타입)와 연결되어 있다.

  • 모든 객체는 [[Prototype]] 이라는 내부 슬롯을 가진다.
  • [[Prototype]] 에 저장되는 프로토타입은 객체 생성방식에 따라 프로토타입이 결정된다.

💡 모든 객체는 하나의 프로토타입을 갖는다. > 모든 프로토타입은 생성자 함수와 연결되어 있다. > 객체와 프로토타입과 생성자 함수는 서로 연결되어 있는 존재이다.

  • [[Prototype]] 내부 슬롯에 직접 접근 할 수 없지만 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입에 간접적으로 접근 가능
  • 프로토타입은 자신의 constructor 프로퍼티를 통해 생성자 함수에 접근할 수 있고, 생성자 함수는 자신의 prototype 프로퍼티를 통해 프로토타입에 접근할 수 있다.

prototype: 클래스에서 인스턴스에서 물려줄 자신의 특징인 속성과 메서드, 생성자 함수 객체만이 소유하는 특권(모든 객체는 하나의 프로토타입을 갖는다.)
proto : 클래스로부터 인스턴스가 물려받은 특징인 속성과 메서드

프로토 접근 프로퍼티

__proto__

  • Object.prototype의 접근자 프로퍼티로써 getter/setter 함수라고 부르는 접근자 함수를 통해 [[Prototype]] 내부 슬롯의 값, 프로토타입을 취득하거나 할당할 수 있다.
  • 모든 객체는 소유하는 것이 아니라 상속을 통해 Object.prototype의 프로퍼티를 사용할 수 있다.

✅ Object.prototype
모든 객체는 프로토타입 계층 구조인 프로토타입 체인에 묶여있다.

  • __proto__ 접근자 프로퍼티가 가리키는 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다.
  • 프로토타입의 체인의 종점이자 최상위 객체는 Object.prototype 이며, 이 객체의 프로퍼티와 메서드는 모든 객체에 상속된다.

✅ 프로토타입 체인

  • 단방향 Linked List 로 구현되어야 한다. -> 검색방향이 한쪽방향으로만
  • 서로가 자신의 프로토타입이 되는 프로토타입 체인이 만들어지면 사이클이 발생하는 종점이 존재하게 된다.
  • 무조건적으로 프로토타입을 교체할 수 없도록 proto 접근자 프로퍼티를 통해 프로토타입에 접근하고 교체하도록 구현되어 있다.

DOM 에서

let div = document.createElement('div');
document.body.append(div);
div.textContent = '코드스테이츠에서는 몰입의 즐거움을 느낄 수 있습니다.';
div.addEventListener('click', () => console.log('몰입을 하면 놀라운 일이 생깁니다.'));

div.__proto__ === HTMLElement.prototype // true
  1. DOM에서는 new 가 아니라 createElement() 를 사용하여 인스턴스 생성
  2. textContent() 메서드를 사용할 수 있는 이유는 Node 를 상속받았기 때문
  3. addEventListener() 메서드를 사용할 수 있는 이유는 EventTarget 을 상속받았기 때문

⭐️ proto 와 prototype

구분소유사용주체사용목적
__proto___ 접근자 프로퍼티모든 객체프로토타입의 참조모든 객체객체가 자신의 프로토타입에 접근 혹은 교체하기 위해
prototype 프로퍼티constructor프로토타입의 참조생성자 함수생성자 함수가 자신이 생성할 인스턴스의 프로토타입을 할당하기 위해



Ex1.

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

me.constructor === Person  //true 
me.__proto__ === Person.prototype   //true
me.__proto__.__proto__ === Object.prototype//true 
// me 인스턴스를 생성하면 person.prototype 과 연결되어
//person.prototype 의 constructor 프로퍼티를 상속받아 사용할 수 있다.
1. Person 생성자 함수는 new 키워드를 이용하여 me 인스턴스를 생성한다.

ㄴ 이때 me 인스턴스는 프로토타입의 constructor 프로퍼티를 통하여 생성자 함수와 연결된다.
2. me 인스턴스에는 constructor 프로퍼티가 없지만 , me 인스턴스의 프로토타입인 Person.prototype 에는 constructor 프로퍼티를 가진다.
3. 따라서 me 인스턴스는 프로토타입인 Person.property 의 constructor 프로퍼티를 상속받아 사용할 수 있다.


Ex2.

class Human {
    constructor(name, age){
        this.name = name; 
        this.age = age;
    }
    sleep(){ return `${this.name}이(가) 잠을 잡니다.`}
}

class Student extends Human{
    constructor(name, age, grade){
        super(name, age);
        this.grade = grade;
    }
    study(num){
        this.grade = this.grade + num;
        return `${this.name}의 성적이 ${num}만큼 올라 ${this.grade}이 되었습니다.`
    }
}

let mincoding = new Student('민학생', 19, 70);

mincoding.__proto__ === Student.prototype  //true
mincoding.__proto__.__proto__ === Human.prototype //true
mincoding.__proto__.__proto__.__proto__ === Object.prototype //true



상속 extends, super 키워드

✅ extends
클래스의 자식 클래스를 생성할 때 사용하며, 부모 클래스를 상속받는다는 의미를 가진 키워드

✅ super
부모 클래스의 함수를 호출 때 사용하며, 자식 클래스가 부모 클래스의 속성과 메서드를 가져오겠다는 의미를 가진 키워드

  • 생성자 함수 내에서 한 번만 사용할 수 있다.
  • 생성자 함수 내에서 super 키워드를 호출하면 부모 클래스의 생성자 함수를 호출한다.
  • this 키워드가 사용되기 전에 사용되어야 한다. 그렇지 않으면, reference 오류가 발생한다.

0개의 댓글