자바스크립트에서는 class가 태초에 없었기 때문에, 객체를 상속하기 위한 방법으로 prototype이라는 숨김 프로퍼티를 이용했다.
숨김프로퍼티는 개발자가 값을 설정하거나 변경할 수 없는데 원칙인데, 특별한 이름인 __proto__를 사용하여 값을 설정할 수 있다.
let animal = {
eat: true,
}
let rabbit = {
jump :true
}
rabbit.__proto__ = animal;
console.log(rabbit.eat) // true
객체는 기본적으로 자신에게 프로퍼티를 찾아보고, 없다면 [[Prototype]에서 찾아본다.
__proto__ 는 [[Prototype]]용 getter, setter 이다. ( __proto__ != [[Prototype]])
아래처럼 생성시에 바로 지정할 수 도있다.
let animal = {
eats: true,
walk() {
alert("동물이 걷습니다.");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
// 메서드 walk는 rabbit의 프로토타입인 animal에서 상속받았습니다.
rabbit.walk(); // 동물이 걷습니다.
for..in 의 순회대상에 포함된다
for...in 은 열거 가능한 프로퍼티만 순회 대상에 포함하기 때문이다.
(Object.prototype 에있는 메서드들은 enumerable 플래그가 false이다)
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
// Object.keys는 객체 자신의 키만 반환합니다.
console.log(Object.keys(rabbit)); // jumps
// for..in은 객체 자신의 키와 상속 프로퍼티의 키 모두를 순회합니다.
for(let prop in rabbit) console.log(prop); // jumps, eats
hasOwnProperty()는 false
이와같이 객체를 대상으로 무언가를 하는 메서드든 상속 프로퍼티를 제외한다.
console.log(rabbit.hasOwnProperty('eats')) // false
Object.keys, Object.values 등
함수의 prototype 프로퍼티
함수를 new 키워드와 함께 사용하여, 생성자함수로 객체를 만들때 또한 prototype을 지정할 수 있다.
여기서 protptype은 함수의 일반 프로퍼티를 말하고, new 를통해서 만들면, 새로운객체는 함수의 prototype 프로퍼티를 참조하여 연결한다.
만약, 설정하지 않으면 default값은 자기자신이다.
function Rabbit() {
this.name = 'rabbit'
}
console.log(Rabbit.prototype.constructor == Rabbit) // true
/* 디폴트 prototype
Rabbit.prototype = { constructor: Rabbit };
*/
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("흰 토끼"); // rabbit.__proto__ == animal
alert( rabbit.eats ); // true
참고로 일반 객체에는 이와같은방식으로 동작하지 안흔ㄴ다.
let user = {
name: "John",
prototype: "Bla-bla" // 마술은 일어나지 않습니다.
};
내장 객체의 프로토타입
흔히 object는 기본적으로 제공되는 메서드가있다.
이는 객체는 Object.prototype을 prototype으로 가지고있기 때문이다.
또 Array, Date, Function과 같은 다른 내장 객체들 역시 프로토타입에 메서드들을 저장해둔다.
let obj = {};
alert(obj.__proto__ === Object.prototype); // true
alert(obj.toString === obj.__proto__.toString); //true
alert(obj.toString === Object.prototype.toString); //true
아래와같이 확인해볼 수 있다.
let arr = [1, 2, 3];
// arr은 Array.prototype을 상속받았나요?
alert( arr.__proto__ === Array.prototype ); // true
// arr은 Object.prototype을 상속받았나요?
alert( arr.__proto__.__proto__ === Object.prototype ); // true
// 체인 맨 위엔 null이 있습니다.
alert( arr.__proto__.__proto__.__proto__ ); // null
콘솔에서 보이는 __proto__ 가 이런것들이다.
+ 원시값들은 래퍼 객체를 통해서 prototype에 접근가능하다.
네이티브 프로로타입 변경도 가능하다.
하지만 이렇게 네이티브 프로토타입을 변경하는것은 전역적으로 영향을 미치기 때문에 좋지 않은 방법이다.
String.prototype.show = function() {
alert(this);
};
"BOOM!".show(); // BOOM!
폴리필은 이런 속성을 변경하여 구현된다.
call, apply 처럼 메서드를 빌려올 수 있다.
let obj = {
0: "Hello",
1: "world!",
length: 2,
};
obj.join = Array.prototype.join;
alert( obj.join(',') ); // Hello,world!
'Archive' 카테고리의 다른 글
class의 정적 메서드, 정적 프로퍼티 (0) | 2022.09.03 |
---|---|
클래스 문법 (0) | 2022.09.03 |
함수 바인딩 (0) | 2022.09.01 |
call/apply 와 데코레이터, 포워딩 (0) | 2022.09.01 |
잘안알려진 함수특성 (0) | 2022.08.31 |