🔖 Before start
자바스크립트는 프로토타입 기반 객체 지향 언어다. 자바스크립트에서 원시 타입을 제외한 나머지 값은 모두 객체로, 자바스크립트를 이루는 거의 모든 것이 객체라고 볼 수 있다.
객체 지향 프로그래밍과 자바스크립트 프로토타입 개념에 대해 알아보자.
객체 지향 프로그래밍은 프로그램을 독립적인 단위(객체)의 집합으로 표현하는 패러다임을 말한다.
프로그램에 필요한 속성을 간추려내는 추상화 작업을 통해 객체를 생성한다.
const person = {
name:'Yeji',
sex:'Female',
introduce(){
console.log(`Hi, I'm ${this.name}`);
}
};
name
과 sex
는 Person의 상태를 나타내는 데이터고, introduce
는 동작이다.
객체 지향 프로그래밍은 객체의 상태를 나타내는 데이터와 그 데이터를 조작할 수 있는 동작을 하나의 단위로 묶는다. 따라서 객체란, 상태 데이터와 동작을 하나의 논리적인 단위로 묶은 자료구조라고 할 수 있다.
객체는 독립적으로 사용될 수 있지만 다른 객체와의 관계성을 가질 수도 있으며, 다른 객체의 상태나 동작을 상속받아 사용할 수도 있다.
상속은 객체 지향 프로그래밍의 핵심 개념으로 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 뜻한다.
상속을 통해 코드 재사용성을 높이며, 불필요한 코드를 줄일 수 있다.
다음과 같이 Person
생성자 함수를 선언했을 때 생성자 함수가 생성하는 모든 객체는 age
프로퍼티와 getAge
메서드를 갖는다. 그런데 객체마다 getAge
메서드를 중복으로 선언하는 문제가 발생한다.
function Person(age) {
this.age = age
this.getAge = function () {
return 'I am ' + this.age
}
}
const yeji = new Person(10)
console.log(yeji.getAge()) // I am 10
const yzii = new Person(20)
console.log(yeji.getAge === yzii.getAge) // false
결국 똑같은 작업을 하는 함수기 때문에 중복으로 선언할시 메모리 낭비가 발생한다. 이를 프로토타입의 상속을 통해 해결할 수 있다.
function Person(age) {
this.age = age
}
Person.prototype.getAge = function getAge() {
return 'I am ' + this.age
}
const yeji = new Person(10)
const yzii = new Person(20)
console.log(yeji.getAge === yzii.getAge) // true
프로토타입은 Person
생성자 함수의 prototype
속성에 바인딩되어 있다.
Person
생성자 함수가 생성한 모든 인스턴스는 Person.prototype
으로부터 getAge
메서드를 상속 받는다.
결국 age
프로퍼티만 개별적으로 소유하고 동일한 getAge
메서드는 상속을 통해 공유하며 사용한다.
프로토타입 객체, 즉 프로토타입은 객체 간의 상속을 구현하기 위해 사용된다.
프로토타입은 어떤 객체의 상위 객체 역할을 하는 객체로, 프로토타입을 상속받은 하위 객체는 상위 객체의 프로퍼티를 자유롭게 사용할 수 있다.
모든 객체는 하나의 프로토타입을 가지며, 모든 프로토타입은 생성자 함수와 연결되어 있다.
한국말이지만 아무리 읽어도 이해가 가지 않는다. 다음 예시를 봐보자.
var person = {
name: 'Lee',
gender: 'male',
sayHello: function(){
console.log('Hi! my name is ' + this.name);
}
};
console.log(person.__proto__ === Object.prototype); // true
1️⃣ person
은 new Object()
생성자 함수에 의해 생성된다.
2️⃣ person
은 __proto__
라는 내부 링크를 통해 생성자 함수의 prototype
속성에 접근할 수 있다.
3️⃣ 이 때 Object.prototype
을 프로토타입 객체라고 한다.
4️⃣ 따라서 모든 객체는 하나의 프로토타입을 가지며, 모든 프로토타입은 생성자 함수와 연결되어 있다.
그림과 같이 모든 프로토타입은 constructor
프로퍼티를 갖는다. constructor
는 자신이 참조하고 있는 생성자 함수를 가리키며, 함수 객체가 생성될 때 연결이 이루어진다.
결국 Object.prototype
과 person.__proto__
는 동일한 프로토타입을 가리킨다고 볼 수 있는데, 프로토타입을 사용하는 주체로 구분할 수 있겠다.
프로퍼티 | 소유 | 사용 주체 | 사용 목적 |
---|---|---|---|
__proto__ | 모든 객체 | 모든 객체 | 자신의 프로토타입에 접근 |
prototype | constructor | 생성자 함수 | 자신이 생성할 객체의 프로토타입 할당 |
프로토타입 체인이란, 객체의 프로퍼티나 메서드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티나 메서드가 없으면 [[Prototype]] 내부 슬롯의 참조에 상위 프로토타입으로 접근하는 행위를 말한다.
ary = []
console.log(ary.hasOwnProperty('hasOwnProperty')) // false
console.log(ary.hasOwnProperty('length')) // true
ary
에는 hasOwnProperty
메서드가 없다. 그런데 hasOwnProperty
메서드를 사용할 수 있다. 어떻게 된 일일까?
hasOwnProperty
메서드를 호출하면 자바스크립트 엔진은 다음과 같이 동작한다.
1️⃣ ary
객체에서 hasOwnProperty
를 검색한다.
2️⃣ ary
객체에 해당 메서드가 없기 때문에 프로토타입 체인을 따라 [[Prototype]]
내부 슬롯을 통해 Object.prototype
으로 이동해 hasOwnProperty
검색한다.
자바스크립트 모든 객체의 체인은 Object.prototype
에서 끝난다. 따라서 Object.prototype
은 프로토타입 체인의 종점으로, [[Prototype]]
내부 슬롯으로 접근하면 null
값이 나온다.