객체지향프로그래밍 OOP에 대해서 배우고 나면 class에 대한 개념을 배우게 된다. 이와 연관된 언어로는 Java, Python 등이 해당된다.
그런데 JavaScript는 프로토타입 기반 언어라고 한다.
그렇다면 프로토타입이란 대체 무엇일까?
왜 class기반이 아니고 또 다른 기반으로 사용하는걸까?
자바스크립트는 클래스를 통해 상속하는 것이 아니고 프로토타입을 통해서 한다고 하니, 자바스크립트를 이해하려면 이 개념을 확실히 알아야 겠다고 생각했다. 그러던 중 한 아티클을 발견하게 됐는데, 이 글은 프로토타입의 등장부터 설명하여 개념을 이해하는 데 많은 도움이 됐다.
자바스크립트는 왜 프로토타입을 선택했을까 - 임성묵
객체를 바라보는 관점에 따라 기반방식이 달라졌다.
- chair
: '이데아(Idea)' 에 존재하는 본질적이고 추상적인 '의자'. 현실세계에 존재하지 않음.- a chair, the chair, chairs
: 현실에 존재하는 다양한 의자들.
플라톤의 '이데아' 이론을 중심으로 개념이 시작된다. 추상적인 이데아 - 현실에 존재하는 것을 이분법적으로 구분한 것이다.
Classification 분류
: 개체의 속성이 동일하면, 같은 범주에 속한다. 범주는 정의와 구별의 합.
- 위 설명에서의 속성이 class의 property속성이다
플라톤의 이데아 이론에서 발전하여 아리스토텔레스가 '분류'라는 개념으로 정립했다. class 키워드가 여기서 나왔음을 유추할 수 있다.
class Chair { // 이데아에 존재 - 클래스
...
}
Chair myChair = new Chair(); // 현실세계(Heap 메모리)에 존재 - 인스턴스
의미사용이론 : 사용에 의해 의미가 결졍된다.
- 단어의 진정한 본래 의미란 없고, 상황과 맥락(Context)에 따라서 결정된다.
이는 아리스토텔레스의 Classification 분류이론을 반박하여 나온 이론이다.
"공유 속성의 관점에선 정의하기 어려운 개념이 있다. 올바른 분류란 없다"
예를 들어 '승자가 없는 게임'에선 공유 속성이 없다. 이 외에도 '예술'은 공통된 속성을 규정할 수가 없다.
이러한 '정확한 분류란 없다'라는 한계점에 대해서 의미사용이론이란 대안을 제시한 것이다.
- 비트겐슈타인의 예) "벽돌!" 을 외쳤을 때 상황,맥락(Context)에 따른 의미
(벽돌이 필요할 때) : 벽돌을 줘
(벽돌로 보수해야 할 때) : 벽돌을 채워
(벽돌이 떨어질 때) : 벽돌을 피해
*여기의 상황=맥락(Context)으로 실행컨텍스트(Execution Context)를 설명할 수 있는 것이다.
대상을 분류할 때 속성이 아닌, 가족 유사성을 통해 분류된다.
예) 가족
가족들이 모두 공유하는 공통 속성은 없다. 검은머리, 안경, 수염의 전형적인 특징을 통해 가족으로 분류한다. 공통된 속성은 없더라도 전형적인 특징을 통해 '가족'으로 분류한다
이렇게 비트겐슈타인은 의미사용이론, 가족유사성이론을 정립했다.
- 가장 좋은 보기를 원형(Prototype) 으로 선택
- 맥락(Context)에 따라 의미가 달라짐
1975년 로쉬가 비트겐슈타인의 의미사용이론, 가족유사성을 정리하여 나온 이론이다.
가족유사성
가족유사성이 높은 순서대로 분류했을때 가장 높은 등급이 원형 Prototype 이다.
객체는 '정의'로 분류되는 것이 아닌, 좋은 '보기(원형)'로부터 범주화된다
의미사용이론
여기에 더해 '어떤 상황 맥락(Context)이냐' 에 따라 의미가 달라진다
같은 단어(식별자)라 할지라도 누가 어떤 상황(context)에서 사용하느냐에 따라 의미(값)가 달라진다.
- 실행컨텍스트의 LexicalEnvironment에서 상위 스코프를 저장해두므로 맥락/바깥 환경을 참조할 수 있게 된다.
모든 객체들이 메서드,속성을 상속받기 위한 템플릿으로 prototype object를 가진다는 뜻
ex) Array.prototype.pop()
JavaScript는 prototype 기반 언어
JS는 prototype 기반으로 상속을 흉내내도록 구현한다.
ES2015부터 class 키워드를 지원하기 시작했으나, 문법적인 양념일 뿐이며 JS는 여전히 프로토타입 기반의 언어다.
: 새로운 객체가 만들어지기 위해 원형이 되는 객체
메서드와 속성들이 모여있는 것
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
Human 클래스 | Array(배열) 클래스 | |
---|---|---|
클래스 | Human | Array |
프로토타입 | Human.prototype.eat | Array.prototype.push (.slice .map ...) |
인스턴스 | adel.eat | arr.push (.slice .map ...) |
__proto__
원형객체로 연결하는 숨겨진 Prototype Link
let kimcoding = new Human(); Human.prototype === kimcoding.__proto__
__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__
으로 연결됐기 때문에 사용할 수 있다
Object.prototype.__proto__
는 더이상 사용하지 않길 바라며, __proto__
생성방법객체.__proto__
를 자동으로 생김const newObj =. Object.create(oldObj)
newObj.__proto__ === oldObj
__proto__
생성됨function Person() {}
const haha = new Person('haha');
상속을 통해 상위 프로토타입으로 연속해서 이어지는 관계
- 상속과 프로토타입 - mdn 참고로 작성
__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
http://insanehong.kr/post/javascript-prototype/
사진출처 | [Javascript ] 프로토타입 이해하기 - 오승환
프로토타입: [[Prototype]], proto, prototype 프로퍼티