함수의 prototype 프로퍼티

RHUK2·2022년 4월 14일
0

Javascript

목록 보기
40/56

📚 Reference


javascript.info, https://ko.javascript.info/function-prototype

참고 사이트에 내용을 개인적으로 복습하기 편하도록 재구성한 글입니다.
자세한 설명은 참고 사이트를 살펴보시기 바랍니다.


함수의 prototype 프로퍼티


생성자 "함수"를 사용해 객체를 만든 경우에 프로토타입이 어떻게 동작하는지에 대해 알아보겠습니다. 생성자 함수로 객체를 만들었을 때 리터럴 방식과 다른점은 💥 생성자 함수의 프로토타입이 객체인 경우에 new 연산자를 사용해 만든 객체는 생성자 함수의 프로토타입 정보를 사용해 [[Prototype]]을 설정한다는 것입니다.


🔥 주의

자바스크립트가 만들어졌을 당시엔 프로토타입 기반 상속이 자바스크립트의 주요 기능 중 하나였습니다.

그런데 과거엔 프로토타입에 직접 접근할 수 있는 방법이 없었습니다. 그나마 믿고 사용할 수 있었던 방법은 생성자 함수의 "prototype" 프로퍼티를 이용하는 방법뿐이었죠. 많은 스크립트가 아직 이 방법을 사용하는 이유가 여기에 있습니다.


생성자 함수(F)의 프로토타입을 의미하는 F.prototype에서 "prototype"F에 정의된 일반 프로퍼티라는 점에 주의해 글을 읽어 주시기 바랍니다. F.prototype에서 "prototype"은 객체의 숨김 프로퍼티인 [[Prototype]]과 이름만 같을 뿐 실제론 다른 우리가 익히 알고있는 일반적인 프로퍼티입니다.

let animal = {
  eats: true
};

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

Rabbit.prototype = animal;

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

alert( rabbit.eats ); // true

Rabbit.prototype = animalnew Rabbit을 호출해 만든 새로운 객체의 [[Prototype]]animal로 설정하라."는 것을 의미합니다.

그림으로 나타내면 다음과 같습니다.

여기서 가로 화살표는 일반 프로퍼티인 "prototype"을, 세로 화살표는 [[Prototype]]을 나타냅니다. 세로 화살표는 rabbitanimal을 상속받았다는 것을 의미합니다.


🔥 F.prototypenew F를 호출할 때만 사용됩니다.

F.prototype 프로퍼티는 new F를 호출할 때만 사용됩니다. F를 호출할 때 만들어지는 새로운 객체의 [[Prototype]]을 할당해 주죠.

새로운 객체가 만들어진 후에 F.prototype 프로퍼티가 바뀌면(F.prototype = <another object>) new F를 호출해 만드는 또 다른 새로운 객체는 를 [[Prototype]]으로 갖게 됩니다. 다만, 기존에 있던 객체의 [[Prototype]]은 그대로 유지됩니다.


함수의 디폴트 프로퍼티 prototype과 constructor 프로퍼티


개발자가 특별히 할당하지 않더라도 모든 함수는 기본적으로 "prototype" 프로퍼티를 갖습니다.

디폴트 프로퍼티 "prototype"constructor 프로퍼티 하나만 있는 객체를 가리키는데, 여기서 constructor 프로퍼티는 함수 자신을 가리킵니다.

이 관계를 코드와 그림으로 나타내면 다음과 같습니다.

function Rabbit() {}

/* 디폴트 prototype
Rabbit.prototype = { constructor: Rabbit };
*/

예시를 실행해 직접 확인해봅시다.

function Rabbit() {}
// 함수를 만들기만 해도 디폴트 프로퍼티인 prototype이 설정됩니다.
// Rabbit.prototype = { constructor: Rabbit }

alert( Rabbit.prototype.constructor == Rabbit ); // true

특별한 조작을 가하지 않았다면 new Rabbit을 실행해 만든 토끼 객체 모두에서 constructor 프로퍼티를 사용할 수 있는데, 이때 [[Prototype]]을 거칩니다.

function Rabbit() {}
// 디폴트 prototype:
// Rabbit.prototype = { constructor: Rabbit }

let rabbit = new Rabbit(); // {constructor: Rabbit}을 상속받음

alert(rabbit.constructor == Rabbit); // true ([[Prototype]]을 거쳐 접근함)


constructor 프로퍼티는 기존에 있던 객체의 constructor를 사용해 새로운 객체를 만들때 사용할 수 있습니다.

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

let rabbit = new Rabbit("흰 토끼");

let rabbit2 = new rabbit.constructor("검정 토끼");

이 방법은 객체가 있는데 이 객체를 만들 때 어떤 생성자가 사용되었는지 알 수 없는 경우(객체가 서드 파티 라이브러리에서 온 경우 등) 유용하게 쓸 수 있습니다.

"constructor"를 이야기 할 때 가장 중요한 점은 자바스크립트는 💥 알맞은 "constructor" 값을 보장하지 않는다는 점입니다.

함수엔 기본으로 "prototype"이 설정된다라는 사실 그게 전부입니다. "constructor"와 관련해서 벌어지는 모든 일은 전적으로 개발자에게 달려있습니다.

함수에 기본으로 설정되는 "prototype" 프로퍼티 값을 다른 객체로 바꿔 무슨일이 일어나는지 살펴봅시다. new를 사용해 객체를 만들었지만 이 객체에 "constructor"가 없는 것을 확인할 수 있습니다.

function Rabbit() {}
Rabbit.prototype = {
  jumps: true
};

let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // false

이런 상황을 방지하고 constructor의 기본 성질을 제대로 활용하려면 "prototype"에 뭔가를 하고 싶을 때 "prototype" 전체를 덮어쓰지 말고 디폴트 "prototype"에 원하는 프로퍼티를 추가, 제거해야 합니다.

function Rabbit() {}

// Rabbit.prototype 전체를 덮어쓰지 말고
// 원하는 프로퍼티가 있으면 그냥 추가합니다.
Rabbit.prototype.jumps = true
// 이렇게 하면 디폴트 프로퍼티 Rabbit.prototype.constructor가 유지됩니다.

실수로 "prototype"을 덮어썼다 하더라도 constructor 프로퍼티를 수동으로 다시 만들어주면 constructor를 다시 사용할 수 있습니다.

Rabbit.prototype = {
  jumps: true,
  constructor: Rabbit
};

// 수동으로 constructor를 추가해 주었기 때문에 우리가 알고 있던 constructor의 특징을 그대로 사용할 수 있습니다.
profile
생각 많이 하지 않기 😎

0개의 댓글