본문 바로가기
Archive

prototype 과 상속

by livemehere 2022. 9. 1.

자바스크립트에서는 class가 태초에 없었기 때문에, 객체를 상속하기 위한 방법으로 prototype이라는 숨김 프로퍼티를 이용했다.

숨김프로퍼티는 개발자가 값을 설정하거나 변경할 수 없는데 원칙인데, 특별한 이름인 __proto__를 사용하여 값을 설정할 수 있다.

let animal = {
    eat: true,
}

let rabbit = {
    jump :true
}

rabbit.__proto__ = animal;

console.log(rabbit.eat) // true

객체는 기본적으로 자신에게 프로퍼티를 찾아보고, 없다면 [[Prototype]에서 찾아본다.

__proto__ 는 [[Prototype]]용 getter, setter 이다. ( __proto__ != [[Prototype]])

 

아래처럼 생성시에 바로 지정할 수 도있다.

let animal = {
  eats: true,
  walk() {
    alert("동물이 걷습니다.");
  }
};

let rabbit = {
  jumps: true,
  __proto__: animal
};

// 메서드 walk는 rabbit의 프로토타입인 animal에서 상속받았습니다.
rabbit.walk(); // 동물이 걷습니다.

 

for..in 의 순회대상에 포함된다

for...in 은 열거 가능한 프로퍼티만 순회 대상에 포함하기 때문이다.

(Object.prototype 에있는 메서드들은 enumerable 플래그가 false이다)

let animal = {
    eats: true
};

let rabbit = {
    jumps: true,
    __proto__: animal
};

// Object.keys는 객체 자신의 키만 반환합니다.
console.log(Object.keys(rabbit)); // jumps

// for..in은 객체 자신의 키와 상속 프로퍼티의 키 모두를 순회합니다.
for(let prop in rabbit) console.log(prop); // jumps, eats

 

hasOwnProperty()는 false

이와같이 객체를 대상으로 무언가를 하는 메서드든 상속 프로퍼티를 제외한다.

console.log(rabbit.hasOwnProperty('eats')) // false

Object.keys, Object.values 등

 

함수의 prototype 프로퍼티

함수를 new 키워드와 함께 사용하여, 생성자함수로 객체를 만들때 또한 prototype을 지정할 수 있다.

여기서 protptype은 함수의 일반 프로퍼티를 말하고, new 를통해서 만들면, 새로운객체는 함수의 prototype 프로퍼티를 참조하여 연결한다.

만약, 설정하지 않으면 default값은 자기자신이다.

function Rabbit() {
    this.name = 'rabbit'
}

console.log(Rabbit.prototype.constructor == Rabbit) // true

/* 디폴트 prototype
Rabbit.prototype = { constructor: Rabbit };
*/
let animal = {
  eats: true
};

function Rabbit(name) {
  this.name = name;
}

Rabbit.prototype = animal;

let rabbit = new Rabbit("흰 토끼"); //  rabbit.__proto__ == animal

alert( rabbit.eats ); // true

 

참고로 일반 객체에는 이와같은방식으로 동작하지 안흔ㄴ다.

let user = {
  name: "John",
  prototype: "Bla-bla" // 마술은 일어나지 않습니다.
};

 

내장 객체의 프로토타입

흔히 object는 기본적으로 제공되는 메서드가있다.

이는 객체는 Object.prototype을 prototype으로 가지고있기 때문이다.

또 Array, Date, Function과 같은 다른 내장 객체들 역시 프로토타입에 메서드들을 저장해둔다.

let obj = {};

alert(obj.__proto__ === Object.prototype); // true

alert(obj.toString === obj.__proto__.toString); //true
alert(obj.toString === Object.prototype.toString); //true

 

아래와같이 확인해볼 수 있다.

let arr = [1, 2, 3];

// arr은 Array.prototype을 상속받았나요?
alert( arr.__proto__ === Array.prototype ); // true

// arr은 Object.prototype을 상속받았나요?
alert( arr.__proto__.__proto__ === Object.prototype ); // true

// 체인 맨 위엔 null이 있습니다.
alert( arr.__proto__.__proto__.__proto__ ); // null

 

콘솔에서 보이는 __proto__ 가 이런것들이다.

 

+ 원시값들은 래퍼 객체를 통해서 prototype에 접근가능하다.

 

네이티브 프로로타입 변경도 가능하다.

하지만 이렇게 네이티브 프로토타입을 변경하는것은 전역적으로 영향을 미치기 때문에 좋지 않은 방법이다.

String.prototype.show = function() {
  alert(this);
};

"BOOM!".show(); // BOOM!

폴리필은 이런 속성을 변경하여 구현된다.

 

 

call, apply 처럼 메서드를 빌려올 수 있다.

let obj = {
  0: "Hello",
  1: "world!",
  length: 2,
};

obj.join = Array.prototype.join;

alert( obj.join(',') ); // Hello,world!

 

 

반응형

'Archive' 카테고리의 다른 글

class의 정적 메서드, 정적 프로퍼티  (0) 2022.09.03
클래스 문법  (0) 2022.09.03
함수 바인딩  (0) 2022.09.01
call/apply 와 데코레이터, 포워딩  (0) 2022.09.01
잘안알려진 함수특성  (0) 2022.08.31