프로토타입

이재윤·2021년 4월 27일
2

JavaScript

목록 보기
1/10
post-thumbnail

자바스크립트의 경우 객체지향 언어이지만, Java와 같은 클래스 기반이 아닌 Prototype 기반 객체지향 언어이다.

💻 Prototype 객체

자바스크립트의 모든 객체는 자신의 부모 객체와 연결되어 있으며, 이러한 부모 객체를 Prototype 객체또는 Prototype이라 한다.

자바스크립트의 모든 객체들은 [[prototype]]이라는 인터널 슬롯을 가지며, __proto__로 접근가능하다. 또한 [[prototype]]의 값은 부모 객체 즉 Prototype 객체를 의미한다.
[[prototype]]의 값은 객체가 생성될 때 객체 생성 방식에 따라 결정된다. 예를 들어, 객체 리터럴에 의해 생성된 객체의 프로토타입은 Object.prototype이며, 생성자 함수로 생성된 객체의 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체이다.

const person = {
	lastName: 'Lee',
  	age: 25
}
console.dir(person)

💻 [[Prototype]] VS prototype 프로퍼티

  • [[Prototype]]
    __proto__로 접근가능한 인터널 슬롯으로 모든 객체가 소유하고 있다. 상속을 위해 사용이 되며, 부모 객체(프로토타입 객체)를 가리키고 있다.
  • prototype 프로퍼티
    자바스크립트의 경우 함수도 객체이다. 따라서 함수 또한 [[Prototype]]을 가지고 있다. 추가적으로 함수객체는 prototype 프로퍼티도 가지고 있다. 함수를 생성자로 사용해 객체를 생성할때 부모역할을 하는 객체(프로토타입 객체)를 가리키고 있다.

둘다 prototype 객체를 가리키고 있지만, [[prototype]]은 생성된 객체의 입장에서 부모의 객체를 가리키고 prototype 프로퍼티의 경우 생성자 함수로 생성될때 부모역할을 할 객체를 가리킨다.

function Person(lastName) {
  this.lastName = lastName
}
const lee = new Person("Lee")
console.dir(Person)
console.dir(lee)

💻 constructor 프로퍼티

프로토타입 객체는 constructor 프로퍼티를 갖는다. constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킨다.

function Person(lastName) {
	this.lastName = lastName
}
const lee = new Person("Lee")

위와 같은 코드를 도식화 해보면 아래와 같다.

  1. Person의 프로토타입 객체는 constructor를 프로퍼티로 가지고 있으며 Person의 생성자 함수를 가리키고 있다.
  2. Person 생성자 함수의 경우 함수 객체이므로, prototype 프로퍼티를 가지고 있으며, prototype 객체를 가리키고 있다.
  3. Person 생성자 함수로 생성된 객체 lee는 객체이므로 [[Prototype]]을 가지고 있으며, 부모 객체인 Person.prototype객체를 가리키고 있다.

따라서 아래와 같은 결과가 나온다.

console.log(Person.prototype.constructor === Person) // true
console.log(lee.constructor === Person) // true

💻 Prototype chain

특정 객체의 프로퍼티나 메소드에 접근하려 할 때, 해당 객체에 접근하려는 프로퍼티나 메소드가 없다면 [[Prototype]]을 따라 부모 객체의 프로퍼티와 메소드를 차례대로 검색한다.

✅ 객체 리터럴 방식으로 생성된 객체의 프로토타입 체인

객체 리터럴 방식으로 객체를 생성할 경우, 자바스크립트는 내부적으로 Object() 생성자 함수를 사용해 객체를 생성한다.

const lee = {
  lastName: "Lee",
  gender: "Male",
  introduce: function() {
    console.log(`I'm ${this.lastName}`)
  }

위와 같이 객체를 생성할 경우 아래와 같이 표현 할 수 있다.

  1. 객체 리터럴로 생성된 lee 객체는 부모 객체로 Object.prototype 객체를 가리키고 있다.
  2. lee 객체에 hasOwnProperty 라는 함수가 없음에도 lee.hasOwnProperty("gender")가 가능한 이유는 프로토타입 체이닝으로 부모 객체를 따라 가면서 hasOwnProperty 메소드를 찾기 때문이다.

따라서 아래와 같은 결과가 나온다.

console.log(lee.__proto__ === Object.prototype) // true
console.log(Object.prototype.constructor === Object) // true
console.log(lee.hasOwnProperty("gender")) // true
console.log(Object.prototype.hasOwnProperty("hasOwnProperty") // true
✅ 생성자 함수로 생성된 객체의 프로토타입 체인

함수를 생성자로 이용해 객체를 생성하기 위해서는 함수를 선언해야 한다. 자바스크립트에서 일반적인 함수 선언방식은 Function()을 생성자 함수로 사용해 선언하는 것과 같다.

function Person(lastName, gender) {
  this.lastName = lastName
  this.gender = gender
  this.introduce = function() {
    console.log(`I'm ${this.lastName}`)
  }
}
const lee = new Person("Lee", "Male")

위와 같이 객체를 생성할 경우 아래와 같이 도식화 할 수 있다.

  1. Person 생성자 함수는 함수 객체이므로, 부모 객체로 Function prototype 객체를 가리키고 있다.
  2. Person prototype 객체는 일반 객체이므로, 부모 객체로 Object prototype 객체를 가리키고 있다.
  3. 생성자 함수로 생성된 lee객체는 부모객체로 Person의 prototype 객체를 가리키고 있다.

따라서 아래와 같은 결과가 나온다.

console.log(lee.__proto__ === Person.prototype) // true
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Person.prototype.constructor === Person) // true
console.log(Person.__proto__ === Function.prototype) // true
console.log(Function.prototype.__proto__ === Object.prototype) // true
console.log(Object.__proto__ === Function.prototype) // true
❗ 모든 객체는 부모 객체인 Object.prototype에서 프로토타입 체인이 끝난다. 따라서 Object.prototype 객체를 프로토타입 체인의 종점 (End of prototype chain)이라 한다.
참고자료 https://poiemaweb.com/js-prototype

0개의 댓글