자바스크립트는 프로토타입 기반의 언어입니다. 자바스크립트에서 모든 객체는 반드시 부모 객체를 가지며, 이 부모 객체를 프로토타입
이라고 합니다. 그리고 자식 객체는 __proto__
접근자를 통해 부모 객체, 즉 자신의 프로토타입에 접근할 수 있습니다.
그럼 프로토타입이 객체의 원형이라고 부르는 이유는 무엇일까요?
위 예제에서 arr와 obj 두 변수가 includes
와 hasOwnProperty
메소드를 사용할 수 있는 이유는 무엇일까요?
자바스크립트에서 배열와 object 자료형에 위 메소드를 쓸 수 있게 처리를 해놓았기 때문입니다. 상속이라는 개념을 통해서 입니다. 이를 확인해보기 위해서 위에서 이야기한__proto__
접근자를 통해서 상속된 부모 객체를 확인할 수 있습니다.
또한 각각 자바스크립트에서 미리 만들어놓은 Array와 Object를 상속받고 있는 것을 알 수 있습니다.
위 예제 처럼 자바스크립트의 객체는 부모 객체를 __proto__
에 상속을 받습니다. 그렇기 때문에 obj의 hasOwnProperty
메소드는 obj의 부모 객체의 메소드를 사용한 것입니다.
이렇듯 자신의 속성에 없으면 부모 객체를 탐색하는 과정을 프로토타입 체이닝
이라고 합니다.
프로토타입 체이닝은 순환참조를 허락하지 않으며, __proto__
는 객체와 null만 받을 수 있습니다. 순환 참조가 발생하면 무한 루프나 스택 오버플로우와 같은 문제가 발생할 수 있기 때문에 이를 금지합니다.
__proto__
속성은 객체나 null만을 값으로 가질 수 있으며, null은 프로토타입 체인의 끝을 나타냅니다.
또한 proto 속성이 단일 객체 참조만을 가질 수 있기 때문에, 다른 클래스 기반 언어에서 볼 수 있는 전통적인 다중 상속을 지원하지 않습니다. Javascript에서는 다중 상속을 직접적으로 구현할 수 없으며, 여러 객체의 속성이나 메소드를 상속 받고 싶을때는 다른 방법(ex. MIXIN)을 사용해야 합니다.
for ... in
은 상속된 부모 객체의 속성도 순회 대상에 포함합니다.
순회 대상에서 제외하고 싶다면 hasOwnProperty(key)
를 이용해야 합니다.
const animal = {
eats: true
};
const rabbit = {
jumps: true,
__proto__: animal
};
// Object.keys
console.log(Object.keys(rabbit)); // jumps
// for..in
for(const prop in rabbit) {
console.log("자신과 부모의 속성이 나옴", prop); // jumps, eats
}
for(const prop in rabbit) {
const isOwn = rabbit.hasOwnProperty(prop);
if (isOwn) {
console.log(`객체 자신의 속성: ${prop}`);
} else {
console.log(`상속된 부모 객체의 속성: ${prop}`);
}
}
자바스크립트의 모든 것이 객체이지만, 원시 데이터 타입(primitive data types)은 객체가 아닙니다. 그럼에도 불구하고, 자바스크립트는 이 원시 값을 필요에 따라 객체처럼 다룰 수 있게 해주는 래퍼(wrapper) 객체를 제공합니다. 그렇기 때문에 string 타입에서 at
와 같은 메소드를 사용할 수 있습니다.
원시 데이터 타입은 객체와 아래와 같은 차이점이 있습니다.
참조
https://ko.javascript.info/
https://developer.mozilla.org/en-US/docs/Glossary/Primitive