[모던자바스크립트] 프로토타입 정리

박재윤·2021년 1월 11일
0

자바스크립트

목록 보기
7/11

[[Prototype]]

자바스크립트 객체는 **[[prototype]]**이라는 숨김 프로퍼티를 갖는다. 이 값은 null이거나 다른 객체를 참조하는데, 다른 객체를 참조하는 경우 참조 대상을 **프로토타입**이라 부른다.

객체에서 프로퍼티를 읽으려고 하는데 해당 프로퍼티가 없으면 자바스크립트는 자동으로 포로토타입에서 프로퍼티를 찾는다.

**[[prototype]]** 는 숨김 프로퍼티이면서 내부 프로퍼티이지만 개발자가 다양한 방법을 사용해 값을 설정할 수 있다.

"**proto"**

__proto__[[Prototype]]용 getter·setter이다.

let animal = {
  eats: true
};
let rabbit = {
  jumps: true
};

rabbit.__proto__ = animal;

최근에는 Object.getPrototypeOfObject.setPrototypeOf를 쓰는 방법을 더 선호한다.

this

this는 프로토타입에 영향을 받지 않는다.

// animal엔 다양한 메서드가 있습니다.
let animal = {
  walk() {
    if (!this.isSleeping) {
      alert(`동물이 걸어갑니다.`);
    }
  },
  sleep() {
    this.isSleeping = true;
  }
};

let rabbit = {
  name: "하얀 토끼",
  __proto__: animal
};

// rabbit의 프로퍼티 isSleeping을 true로 변경합니다.
rabbit.sleep();

alert(rabbit.isSleeping); // ?? 
alert(animal.isSleeping); // ?? 

for ... in

for...in 반복문은 상속 프로퍼티도 순회 대상에 포함시킨다.

대신 obj.hasOwnProperty(key) 를 이용하면 상속 프로퍼티를 순회 대상에서 제외할 수 있다.

let animal = {
  eats: true
};

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

for(let prop in rabbit) {
  let isOwn = rabbit.hasOwnProperty(prop);

  if (isOwn) {
    alert(`객체 자신의 프로퍼티: ${prop}`); // 객체 자신의 프로퍼티: jumps
  } else {
    alert(`상속 프로퍼티: ${prop}`); // 상속 프로퍼티: eats
  }
}

위에서 rabbit을 for ... in을 사용해서 반복문을 돌 때 prop에 hasOwnProperty가 들어갈까?

함수의 prototype 프로퍼티

생성자 함수에 prototype 프로퍼티가 있고 그것이 객체이면 생성자 함수 안에서 만드는 객체의 프로토타입을 prototype 프로퍼티를 이용해서 설정한다.

function sum(a,b){ 
	// prototype : {constructor: sum}
}

prototype constructor

모든 함수는 prototype 프로퍼티를 갖는다. 기본 프로퍼티인 "prototype"은 constructor 프로퍼티 하나만 있는 객체를 가리키는데 constructor 프로퍼티는 함수 자기 자신을 가리킨다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c4ee5e3d-7ba4-4f43-99a3-1d0e033cc921/Untitled.png

constructor 프로퍼티를 이용해서 새로운 객체를 만들 수 있다.

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

Rabbit.prototype = {}

let rabbit = new Rabbit("White Rabbit");
let rabbit2 = new rabbit.constructor("Black Rabbit");

그런데 prototype 프로퍼티에 항상 contstructor가 있도록 자바스크립트가 보장을 해주지는 않는다.

따라서 prototype에 다른 객체를 덮어쓰는 것 보다 prototype에 다른 프로퍼티를 추가하는 것이 좋다.

function Rabbit() {}

// Rabbit.prototype 전체를 덮어쓰지 말고
// 원하는 프로퍼티는 그냥 추가하세요.
Rabbit.prototype.jumps = true
// 이렇게 하면 기본 Rabbit.prototype.constructor가 유지됩니다.

프로토타입 메서드와 "proto"가 없는 객체

proto는 구식이기 때문에 더 사용하는 것을 권장하지 않는다.

대신 아래와 같은 메서드를 사용하는 것이 좋다.

Object.create()로 객체를 만들면 proto getter와 setter를 상속 받지 않는다.

let animal = {
  eats: true
};

// 프로토타입이 animal인 새로운 객체를 생성합니다.
let rabbit = Object.create(animal);

alert(rabbit.eats); // true

alert(Object.getPrototypeOf(rabbit) === animal); // true

Object.setPrototypeOf(rabbit, {}); // rabbit의 프로토타입을 {}으로 바꿉니다.

0개의 댓글