__proto__, Object.hasOwnProperty
Prototype?
그런데 여러분들은 class 대신 prototype을 사용할 수 있다는 것을 들어보았을 것이다. javascript가 prototype 기반의 언어라는 것을 먼저 이해하자. js에서 모든 것은 객체로 다뤄진다. 그런데 js에서의 객체는 Prototype이라는 은닉 속성을 가진다. 이 프로토타입은 자신의 프로토타입이 되는 다른 객체를 가리킨다.
예를 들자면
const a = [];
해당 a를 콘솔에서 출력해보자면 Array가 가지는 __proto__을 상속받았음을 확인할 수 있다.
해당 __proto__에서는 array에서 쓸 수 있는 메서드인 concat, every, fill, filter, find, findIndext 등이 정의되어 있는 것을 확인할 수 있다.
그런데 array의 __proto__ 내부에는 또 다른 __proto__가 있는 것을 확인할 수 있다. 이는 Object의 __proto__이다. array도 결국 객체이므로 객체의 프로토타입을 상속 받은 것이다.
이런 방식으로 프로토타입은 서로 맞물려서 null까지 프로토타입이 연결되고 이러한 연결을 'prototype chain'(프로토타입 체인)이라고 부른다. obj에 prop 속성이없는 경우 JavaScript는 obj .__ proto __. prop를 찾은 다음 obj .__ proto __.__ proto __. prop 등을 찾아 프로토타입 체인을 타고 올라갑니다.
뾰로롱~
prototype 상속
그래서 이러한 프로토타입이 어쨌다는 것인가?
실제로 사용해보도록하자.
let user = {name: "darren", age: 100}
let admin = {name: "darren", age:100, role: 'admin'} // user와 중복
이 부분을 admin 객체의 __proto__ 에 user를 넣어줌으로서 '상속'시킬 수 있다.
let user = {name: "darren", age: 100}
let admin = {role: 'admin'}
admin.__proto__ = user // admin.name, admin.age 접근 가능해짐
admin을 출력해보면 __proto__에 age, name이 들어있는 것을 확인할 수 있다.
Object.hasOwnProperty
객체에 해당 속성이 없으면 __proto__ 체인을 타고 해당 속성을 쭉 찾아 올라가게 된다.
그러나, 프로토타입 체인을 타지 않고 해당 객체에 그 속성의 유무를 체크하려면 Object.hasOwnProrperty 메서드를 사용하면 된다.
let cat = {
teeth: 32
}
let dog = {
__proto__: cat
}
dog.hasOwnProperty("teeth") // false
cat.hasOwnProperty("teeth") // true
그래서 prototype과 class는 무슨 상관이 있는 것인가?
babel을 통해 class를 하위 버전 js로 트랜스파일하면 생성자 함수로 변환된다.
js에서 class를 제공하는 건 다른 코드를 다뤘던 사람들의 편의를 위한 것이지 js에서 클래스의 근본은 프로토타입에 기반한 생성자 함수이다.
따라서 아래 두 코드는 완전히 같다.
function Person(name, age) {
this.name = name;
this.age = age;
}
const me = new Person("darren", 23);
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const me = new Person("darren", 23);
생성자 함수를 콘솔에서 실행해보면 다음과 같이 constructor 부분에 Person 생성자 함수가 들어간 것을 확인할 수 있다.