JavaScript/함수

[JavaScript]프로토타입 체인(Prototype Chain)

DevStory 2022. 7. 5.

프로토타입 체인(Prototype Chain)

JavaScript에서 변수를 객체(배열, 객체, 함수 등)로 선언하면 상위 객체의 프로퍼티를 호출할 수 있는데, 여기서 말하는 상위 객체를 프로토타입이라고 말합니다.

var arr = []; // 배열을 할당했으므로 프로토타입은 Array
var obj = {}; // 객체를 할당했으므로 프로토타입은 Object

console.dir(arr);
console.dir(obj);

[실행 결과]

그리고 상위 객체의 프로퍼티를 호출할 수 있도록 해주는 메커니즘을 프로토타입 체인(Prototype Chain)이라고 말합니다.

var arr = [];
var obj = {};

arr.push(1); // Array는 push() 함수를 사용할 수 있음
obj.push(1); // Object는 push() 함수가 없으므로 TypeError 발생

[에러 내용]

Array에는 push() 함수가 존재하지만, Object에는 push() 함수가 존재하지 않으므로 객체 obj가 push() 함수를 호출하는 경우 위 예제처럼 TypeError가 발생합니다.

 

반면에, 배열 arr은 에러 없이 정상적으로 동작합니다. 프로토타입 체인에 의해 상위 객체의 프로퍼티를 호출할 수 있기 때문입니다.

 

프로토타입에 대한 내용은 아래 포스팅에서 자세하게 설명합니다.

 

[JavaScript]프로토타입(Prototype)이란?

객체(Object) JavaScript의 프로토타입을 설명하기 전에 객체에 대해 살펴봅시다. JavaScript는 배열, 문자열 심지어 함수도 객체로 간주합니다. 다음 예제는 배열 생성 후 요소 추가, 삭제 그리고 요소

developer-talk.tistory.com

다음 내용은 객체 리터럴 방식으로 생성된 객체의 프로토타입 체인과 생성자 함수 방식으로 생성된 객체의 프로토타입 체인에 대해 설명합니다.


객체 리터럴 방식

이번에는 객체 리터럴 방식으로 생성된 객체의 프로토타입 체인에 대해 알아봅시다.

 

다음 예제를 Chrome 개발자 도구에서 실행해봅시다.

var obj = {
  name: 'Bob',
  age: 20,
  show: function() {
    console.log('name: ' + this.name + ' / age: ' + this.age);
  }
}

obj.show();
console.log(obj.hasOwnProperty('name'));
console.log(obj.hasOwnProperty('address'));
obj.sum();

[실행 결과]

객체 obj에는 show() 메서드가 존재하므로 show() 메서드를 정상적으로 호출합니다.

객체 obj에는 sum() 메서드가 존재하지 않으므로 TypeError가 발생합니다.

객체 obj에는 hasOwnProperty() 메서드가 없음에도 정상적으로 실행되었습니다.

 

hasOwnProperty() 함수는 문자열로 넘긴 값이 프로퍼티로 존재하는 경우 true를 반환하고 그렇지 않으면 false를 반환하는 JavaScript 표준 API입니다. 객체 obj에는 name 프로퍼티가 존재하므로 true, address 프로퍼티는 존재하지 않으므로 false가 반환되었습니다.

 

객체 obj가 hasOwnProperty() 메서드를 호출할 수 있었던 이유를 이해하기 위해 프로토타입 체인을 다시 생각해봅시다. 프로토타입 체인은 상위 객체의 prototype 프로퍼티를 호출할 수 있도록 하는 메커니즘입니다.

 

객체 obj는 객체 리터럴 방식으로 생성되었으므로 Object()라는 내장 생성자 함수로 생성되었습니다.

생성자 함수인 Object()도 함수이므로 prototype 프로퍼티가 존재하고 생성자 함수에 의해 생성된 객체는 Object.prototype를 자신의 프로토타입 객체로 연결합니다.

 

다음 사진은 Object의 prototype 프로퍼티에 hasOwnProperty() 함수가 존재한다는 것을 보여줍니다.

객체 리터럴 방식으로 생성된 객체의 동작 방식을 그림으로 나타내면 다음과 같습니다.

 

만약, 아래 그림이 이해안된다면 아래 포스팅에서 객체가 생성되는 과정을 참고해주세요.

 

[JavaScript]생성자 함수와 this(Constructor Function and this)

생성자 함수 JavaScript에서 객체를 생성하는 방법은 객체 리터럴 방식과 생성자 함수를 이용하는 두 가지 방법이 존재합니다. 생성자 함수에 대한 내용은 아래 포스팅에서 자세하게 설명합니다. [

developer-talk.tistory.com

JavaScript에서 프로퍼티나 메서드를 호출했는데, 해당 프로터피 또는 메서드가 없다면 [[Prototype]] 링크를 따라 상위 객체의 prototype 프로퍼티를 차례대로 검색합니다.

 

호출한 프로퍼티 또는 메서드가 상위 객체의 프로퍼티에 존재하는 경우 해당 프로퍼티를 호출하고 그렇지 않으면, obj.sum()처럼 TypeError가 발생하게 됩니다.

 

hasOwnProperty() 함수는 객체 obj에는 없지만, 상위 객체인 Object의 prototype 프로퍼티에 포함되어 있으므로 TypeError가 발생하지 않고 정상적으로 호출됩니다.

 

즉, 호출하는 프로퍼티 또는 메서드가 객체에 없는 경우 [[Prototype]] 링크를 따라 상위 객체의 prototype 프로퍼티를 검색하는 것을 프로토타입 체인이라고 말합니다.

반응형

생성자 함수 방식

객체 리터럴 방식으로 생성된 객체와 생성자 함수 방식으로 생성된 객체는 프로토타입 체인 메커니즘이 조금 다릅니다. 하지만, 상위 객체가 프로토타입이라는 점은 동일합니다.

 

다음 예제는 생성자 함수로 객체를 생성합니다.

function UserInfo(name, age) {
  this.name = name;
  this.age = age;
}

var user = new UserInfo('Bob', 20);

console.log(user.hasOwnProperty('name'));
console.dir(UserInfo.prototype);

[실행 결과]

객체 user는 생성자 함수 UserInfo()에 의해 생성되었습니다. 따라서, 객체의 [[Prototype]]는 UserInfo의 prototype 프로퍼티로 설정됩니다.

 

그런데, UserInfo의 prototype 프로퍼티에는 hasOwnProperty() 함수가 없습니다. 따라서 객체 user가 hasOwnProperty() 함수를 호출하면 TypeError가 발생해야 하는데, 에러가 발생하지 않고 정상적으로 실행되었습니다.

Object.prototype 객체에 포함되어 있는 hasOwnPrototype() 함수가 정상적으로 호출되었으므로 프로토타입 체인이 UserInfo.prototype 객체에서 끝나지 않고 계속 이어진다는 것을 의미합니다.

 

UserInfo.prototype 객체의 [[Prototype]] 프로퍼티를 살펴보면, hasOwnPrototype() 함수가 존재합니다.

function UserInfo(name, age) {
  this.name = name;
  this.age = age;
}

console.dir(UserInfo.prototype);

[실행 결과]

UserInfo.prototype도 객체이므로 상위 객체의 프로퍼티를 호출할 수 있는데, UserInfo.prototype의 상위 객체가 Object인 것이죠.

 

따라서, [[Prototype]] 링크에 의해 객체 user도 hasOwnPrototype() 함수를 호출할 수 있습니다.


프로토타입 체인의 종점

JavaScript에서 프로토타입 체인의 종점은 Object.prototype 객체입니다. 위 예제에서 살펴봤듯이 객체 리터럴 방식이나 생성자 함수를 사용한 방식이나 Object.prototype 객체에서 프로토타입 체인이 끝나므로 Object의 프로퍼티를 사용할 수 있었습니다.


프로토타입 체인 동작 시점

객체의 특정 프로퍼티를 호출하거나 특정 메서드를 호출할 때, 객체에 존재하지 않으면 프로토타입 체인이 발생합니다. 반대로 객체의 특정 프로퍼티에 값을 할당하는 경우에는 프로토타입 체인이 발생하지 않습니다.

 

객체의 특정 프로퍼티에 값을 할당해야하는데, 프로퍼티가 없는 경우 프로퍼티를 동적으로 추가하므로 프로토타입 체인이 발생하지 않습니다.

반응형

댓글