Programming Language/🟨 Javascript

__proto__, Object.hasOwnProperty

DarrenKwonDev 2020. 10. 31. 20:53
 

상속과 프로토타입

Java 나 C++ 같이 클래스 기반의 언어를 사용하던 프로그래머는 자바스크립트가 동적인 언어라는 점과 클래스가 없다는 것에서 혼란스러워 한다. (ES2015부터 class 키워드를 지원하기 시작했으나,

developer.mozilla.org

 

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 생성자 함수가 들어간 것을 확인할 수 있다.