ES6부터 class키워드를 지원하기 시작했으나, 문법적인 양념일뿐이며
자바스크립트는 여전히 프로토타입 기반의 언어이다.
상속 관점에서 자바스크립트의 유일한 생성자는 객체뿐이다.
각각의 객체는 [[Prototype]]이라는 은닉(private) 속성을 가지는데 자신의 프로토타입이 되는 다른 객체를 가리킨다.
그 객체의 프로토타입 또한 프로토타입을 가지고 있고 이것이 반복되다,
결국 null을 프로토타입으로 가지는 오브젝트에서 끝난다.
null은 더 이상의 프로토타입이 없다고 정의되며, 프로토타입 체인의 종점 역할을 한다.
속성 상속
자바스크립트 객체는 속성을 저장하는 동적인 "가방"과 (자기만의 속성이라고 부른다) 프로토타입 객체에 대한 링크를 가진다.
객체의 어떤 속성에 접근하려할 때 그 객체 자체 속성 뿐만 아니라 객체의 프로토타입, 그 프로토타입의 프로토타입 등
프로토타입 체인의 종단에 이를 때까지 그 속성을 탐색한다.
// o라는 객체가 있고, 속성 'a' 와 'b'를 갖고 있다고 하자.
let f = function () {
this.a = 1;
this.b = 2;
}
let o = new f(); // {a: 1, b: 2}
// f 함수의 prototype 속성 값들을 추가 하자.
f.prototype.b = 3;
f.prototype.c = 4;
// f.prototype = {b: 3, c: 4}; 라고 하지 마라, 해당 코드는 prototype chain 을 망가뜨린다.
// o.[[Prototype]]은 속성 'b'와 'c'를 가지고 있다.
// o.[[Prototype]].[[Prototype]] 은 Object.prototype 이다.
// 마지막으로 o.[[Prototype]].[[Prototype]].[[Prototype]]은 null이다.
// null은 프로토타입의 종단을 말하며 정의에 의해서 추가 [[Prototype]]은 없다.
// {a: 1, b: 2} ---> {b: 3, c: 4} ---> Object.prototype ---> null
console.log(o.a); // 1
// o는 'a'라는 속성을 가지는가? 그렇다. 속성의 값은 1이다.
console.log(o.b); // 2
// o는 'b'라는 속성을 가지는가? 그렇다. 속성의 값은 2이다.
// 프로토타입 역시 'b'라는 속성을 가지지만 이 값은 쓰이지 않는다. 이것을 "속성의 가려짐(property shadowing)" 이라고 부른다.
console.log(o.c); // 4
// o는 'c'라는 속성을 가지는가? 아니다. 프로토타입을 확인해보자.
// o.[[Prototype]]은 'c'라는 속성을 가지는가? 가지고 값은 4이다.
console.log(o.d); // undefined
// o는 'd'라는 속성을 가지는가? 아니다. 프로토타입을 확인해보자.
// o.[[Prototype]]은 'd'라는 속성을 가지는가? 아니다. 다시 프로토타입을 확인해보자.
// o.[[Prototype]].[[Prototype]]은 null이다. 찾는 것을 그만두자.
// 속성이 발견되지 않았기 때문에 undefined를 반환한다.
메소드 상속
상속된 함수가 실행 될 때, this 라는 변수는 상속된 오브젝트를 가르킨다.
그 함수가 프로토타입의 속성으로 지정되었다고 해도 말이다.
var o = {
a: 2,
m: function(b){
return this.a + 1;
}
};
console.log(o.m()); // 3
// o.m을 호출하면 'this' 는 o를 가리킨다.
var p = Object.create(o);
// p 는 프로토타입을 o로 가지는 오브젝트이다.
p.a = 12; // p 에 'a'라는 새로운 속성을 만들었다.
console.log(p.m()); // 13
// p.m이 호출 될 때 'this' 는 'p'를 가리킨다.
// 따라서 o의 함수 m을 상속 받으며,
// 'this.a'는 p.a를 나타내며 p의 개인 속성 'a'가 된다.
__proto__와 prototype chain
function doSomething(){}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // add a property onto the object
console.log( doSomeInstancing );
콘솔 실행결과는 다음과 같다.
위의 사진을 보면 doSomeInstancing 객체의 __proto__ 는 doSomething.prototype 이다.
__proto__ 는 뭘까??
우리가 doSomeInstancing의 속성에 접근할때 브라우저는 우선 doSomeInstancing이 그 속성을 갖고있는지 확인한다.
만약 doSomeInstancing이 속성을 갖고있지 않다면,
브라우저는 doSomeInstancing의 __proto__(doSomething.prototype)가 그 속성을 갖고있는지 확인한다.
만약 doSomeInstancing의 __proto__가 브라우저가 찾던 속성을 갖고 있다면,
doSomething의 __proto__가 갖고있는 그 속성을 사용한다.
그렇지 않고, doSomeInstancing의 __proto__가 그 속성을 갖고있지 않을때에는
doSomeInstancing의 __proto__의 __proto__가 그 속성을 갖는지 확인한다.
기본적으로, 어떠한 함수던지 그 함수의 prototype 속성의 __proto__는 window.Object.prototype이다.
그러므로 브라우저는 doSomeInstancing의 __proto__의 __proto__(doSomething.prototype의 __proto__(다시말해, Object.prototype)) 에서 그 속성을 찾아본다.
만약 그 속성을 doSomeInstancing의 __proto__의 __proto__에서 찾을 수 없다면 그다음엔 doSomeInstancing의 __proto__의 __proto__의 __proto__에서 찾을것이다.
하지만 여기서 문제가 발생한다.
doSomeInstancing의 __proto__의 __proto__의 __proto__는 존재할 수 없다
(window.Object.prototype의 __proto__는 null이기 때문).
그제서야, 오직 모든 프로토타입 체인이 검사 되고 브라우저가 더이상 검사할 __proto__가 없을때에서야 브라우저는 우리가 찾던 값이 undefined라고 결론짓는다.
참고: MDN 상속과 프로토타입
'개인공부 > TIL(Today I Learned)' 카테고리의 다른 글
TIL 43일차_1급시민 (0) | 2021.03.02 |
---|---|
TIL 42일차_상속 방법 두가지: pseudoClassical패턴과 ES6+ class문법 (0) | 2021.03.01 |
TIL 40일차_ 객체지향프로그래밍(OOP) (0) | 2021.02.27 |
TIL 39일차_모듈과 CommonJS (0) | 2021.02.26 |
TIL 38일차_package.json (0) | 2021.02.25 |