TIL - prototype은 무엇인가

moontag·2022년 5월 25일
0

JavaScript TIL

목록 보기
16/20
post-thumbnail




객체지향프로그래밍 OOP에 대해서 배우고 나면 class에 대한 개념을 배우게 된다. 이와 연관된 언어로는 Java, Python 등이 해당된다.
그런데 JavaScript는 프로토타입 기반 언어라고 한다.
그렇다면 프로토타입이란 대체 무엇일까?
왜 class기반이 아니고 또 다른 기반으로 사용하는걸까?

자바스크립트는 클래스를 통해 상속하는 것이 아니고 프로토타입을 통해서 한다고 하니, 자바스크립트를 이해하려면 이 개념을 확실히 알아야 겠다고 생각했다. 그러던 중 한 아티클을 발견하게 됐는데, 이 글은 프로토타입의 등장부터 설명하여 개념을 이해하는 데 많은 도움이 됐다.
자바스크립트는 왜 프로토타입을 선택했을까 - 임성묵




OOP의 2가지 기반 방식

객체를 바라보는 관점에 따라 기반방식이 달라졌다.

1. 클래스 기반 OOP

플라톤 - 이데아 Idea

  • chair
    : '이데아(Idea)' 에 존재하는 본질적이고 추상적인 '의자'. 현실세계에 존재하지 않음.
  • a chair, the chair, chairs
    : 현실에 존재하는 다양한 의자들.

플라톤의 '이데아' 이론을 중심으로 개념이 시작된다. 추상적인 이데아 - 현실에 존재하는 것을 이분법적으로 구분한 것이다.

아리스토텔레스 - 분류 Classification

Classification 분류
: 개체의 속성이 동일하면, 같은 범주에 속한다. 범주는 정의와 구별의 합.

  • 위 설명에서의 속성이 class의 property속성이다

플라톤의 이데아 이론에서 발전하여 아리스토텔레스가 '분류'라는 개념으로 정립했다. class 키워드가 여기서 나왔음을 유추할 수 있다.

class Chair {     // 이데아에 존재 - 클래스
... 
}
Chair myChair = new Chair();  // 현실세계(Heap 메모리)에 존재 - 인스턴스




2. 프로토타입 기반 OOP

비트겐슈타인 - 의미사용이론 (the use theory of meaning)

의미사용이론 : 사용에 의해 의미가 결졍된다.

  • 단어의 진정한 본래 의미란 없고, 상황과 맥락(Context)에 따라서 결정된다.

이는 아리스토텔레스의 Classification 분류이론을 반박하여 나온 이론이다.
"공유 속성의 관점에선 정의하기 어려운 개념이 있다. 올바른 분류란 없다"
예를 들어 '승자가 없는 게임'에선 공유 속성이 없다. 이 외에도 '예술'은 공통된 속성을 규정할 수가 없다.
이러한 '정확한 분류란 없다'라는 한계점에 대해서 의미사용이론이란 대안을 제시한 것이다.

  • 비트겐슈타인의 예) "벽돌!" 을 외쳤을 때 상황,맥락(Context)에 따른 의미
    (벽돌이 필요할 때) : 벽돌을 줘
    (벽돌로 보수해야 할 때) : 벽돌을 채워
    (벽돌이 떨어질 때) : 벽돌을 피해

*여기의 상황=맥락(Context)으로 실행컨텍스트(Execution Context)를 설명할 수 있는 것이다.


비트겐슈타인 - 가족유사성 (Family Resemblance)

대상을 분류할 때 속성이 아닌, 가족 유사성을 통해 분류된다.

예) 가족
가족들이 모두 공유하는 공통 속성은 없다. 검은머리, 안경, 수염의 전형적인 특징을 통해 가족으로 분류한다. 공통된 속성은 없더라도 전형적인 특징을 통해 '가족'으로 분류한다
이렇게 비트겐슈타인은 의미사용이론, 가족유사성이론을 정립했다.


Eleanor Rosch - 프로토타입 이론(Prototype theory)

  • 가장 좋은 보기를 원형(Prototype) 으로 선택
  • 맥락(Context)에 따라 의미가 달라짐

1975년 로쉬가 비트겐슈타인의 의미사용이론, 가족유사성을 정리하여 나온 이론이다.

  • 가족유사성
    가족유사성이 높은 순서대로 분류했을때 가장 높은 등급이 원형 Prototype 이다.
    객체는 '정의'로 분류되는 것이 아닌, 좋은 '보기(원형)'로부터 범주화된다

  • 의미사용이론
    여기에 더해 '어떤 상황 맥락(Context)이냐' 에 따라 의미가 달라진다

같은 단어(식별자)라 할지라도 누가 어떤 상황(context)에서 사용하느냐에 따라 의미(값)가 달라진다.

  • 실행컨텍스트의 LexicalEnvironment에서 상위 스코프를 저장해두므로 맥락/바깥 환경을 참조할 수 있게 된다.








prototype 기반 OOP 언어?

모든 객체들이 메서드,속성을 상속받기 위한 템플릿으로 prototype object를 가진다는 뜻
ex) Array.prototype.pop()

  • JavaScript는 prototype 기반 언어

  • JS는 prototype 기반으로 상속을 흉내내도록 구현한다.

  • ES2015부터 class 키워드를 지원하기 시작했으나, 문법적인 양념일 뿐이며 JS는 여전히 프로토타입 기반의 언어다.



1. .prototype

: 새로운 객체가 만들어지기 위해 원형이 되는 객체
메서드와 속성들이 모여있는 것
Array.prototype.push
Array클래스를 만들면 Array.prototype에 메서드들이 담겨있다

class Human {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  eat() {
    console.log(`${this.name} eating dinner`);
  }
}

// instanciation - new Human()
let adel = new Human('Adel', 10); 

Human.prototype.constructor === Human;  // true
Human.prototype === adel.__proto__;    // true
Human.prototype.sleep === adel.sleep;  // true





2. class - prototype - instance 관계

Human 클래스Array(배열) 클래스
클래스HumanArray
프로토타입Human.prototype.eatArray.prototype.push (.slice .map ...)
인스턴스adel.eatarr.push (.slice .map ...)
  • Array는 클래스고, 배열은 Array 클래스의 인스턴스다
    Array.protorype에 push나 pop 등 메서드 사용가능하다





3. __proto__

원형객체로 연결하는 숨겨진 Prototype Link

let kimcoding = new Human();
Human.prototype === kimcoding.__proto__
  • 상위에서 물려받은 객체의 프로토타입에 대한 정보(Prototype Object)를 가리킨다
  • 모든 객체는 __proto__를 통해 연결되어 있기 때문에, 최상위 부모의 프로토타입에 접근할 수 있다.
class Human {
  constructor(name = '나다'){ // name = '나다' 초기값 설정함
    this.name = name;
  }
  eat(){
    return `${this.name} eating!!!`;
  }
}

class Student extends Human {
  construcrot(name){
    super(); // 안에 매개변수를 쓰면 위에 부모에 맞춰서 써야 하므로 그냥 비워두는 게 편하다
  	this.name = name;
  }
  sleep(){
    return `${this.name} sleep~ zzz...`;
  }
}

let kimcoding = new Student('kim');
kimcoding.eat();  // 'kim eating!!!'

위에 예시에서 kimcoding이 부모의 부모메서드인 eat을 참조할 수 있는 것은 __proto__으로 연결됐기 때문에 사용할 수 있다



__proto__ 생성방법

  1. 다른 객체를 바탕으로 객체 생성한 경우
    원형객체가 있다면 객체.__proto__를 자동으로 생김
const newObj =. Object.create(oldObj)
newObj.__proto__ === oldObj



  1. 함수 객체인 경우
    Person 생성시 Person Prototype도 같이 생성됨
    그래서 Person의 prototype <=> Person Protytpe객체의 constructor
    서로 참조하게 됨. 여기서 Person Protytpe객체 안에 __proto__생성됨
function Person() {}


출처


  1. new 함수로 만들어진 객체의 경우
    프로토타입의 체이닝을 통해 원형객체의 속성을 공유할 수 있다
    Person prototype의 constructor를 참조
const haha = new Person('haha');








4. prototype Chain

상속을 통해 상위 프로토타입으로 연속해서 이어지는 관계

  • __proto__ 를 통해 상위 프로토타입을 탐색할 수 있다

  • ECMAScript 2015부터 Object.getPrototypeOf()Object.setPrototypeOf()을 이용하여 접근한다. 이것은 자바스크립트의 표준은 아니나 많은 브라우저에 구현되어 사실상의 표준이 된 속성 __proto__과 동일하다.

  • 프로토타입 체인의 길이는 성능을 저해하지 않도록 줄이는 방법을 고안해야 한다.

  • 빌트인 프로토타입은 새로운 자바스크립트 기능과 호환성을 갖기 위한 이유가 아닌 이상 절대 확장해서는 안된다.

let div = document.createElement('div');  // HTMLDivElement 클래스의 인스턴스

console.log(div.__proto__);  // HTMLDivElement
console.log(div.__proto__.__proto__);  // HTMLElement
console.log(div.__proto__.__proto__.__proto__);  // Element
console.log(div.__proto__.__proto__.__proto__.__proto__);  // Node
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__);  // EventTarget
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);  // Object
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);  // null
  • 최상위는 Object다.
    HTMLDivElement - HTMLElement - Element - Node - EventTarget - Object



Object

  • 프로토타입 체인 구조 때문에 모든 객체는 Object의 자식이다
  • Object Prototype Object에 있는 모든 속성 사용 가능.
    ex) mun.toString();







참조

자바스크립트는 왜 프로토타입을 선택했을까 - 임성묵

[Javascript ] 프로토타입 이해하기

프로토타입 체인을 이용한 상속 - mdn

http://insanehong.kr/post/javascript-prototype/

사진출처 | [Javascript ] 프로토타입 이해하기 - 오승환

프로토타입: [[Prototype]], proto, prototype 프로퍼티








profile
터벅터벅 나의 개발 일상

0개의 댓글