__proto__속성은 다소 구식이기 때문에 더는 사용하지 않는 것이 좋다. 표준에도 관련 내용이 명시되어있다.
모던한 프로토타입 메소드가 없을때는 어쩔수 없이 __proto__를 사용했지만 이제는 프로토타입 메소드를 사용하는 것이 좋다.
__proto__속성을 대체하려면 객체의 [[prototype]]숨김속성을 설정할 수 있어야 한다.
Object.getPrototypeOf(obj);
obj의 [[Prototype]]을 반환한다.
Object.setPrototypeOf(obj, proto);
obj의 [[Prototype]]이 proto가 되도록 설정한다.
Object.create(parObj, [descriptors]);
[[Prototype]]이 parObj를 참조하는 빈 객체를 반환한다. 프로퍼티 설명자를 추가로 넘길 수 있다.
let animal = {
eats: true
};
let obj = Object.create(animal,{
jumps: {
value: true
}
});
console.log(obj.eats, obj.jumps);
생성자함수로 상위객체를 설정하고 new로 객체를 생성하는 것은 다수의 객체를 만들때 사용하는 방법이고 위 방법은 소량의 객체를 만들때 사용하면 좋다.
descriptors로 프로퍼티를 세세하게 설정할 수 있다.
지금까지 객체를 생성하는 방법
new 생성자함수
리터럴객체
Object.create(parObj, [descriptors]);
지금까지 [[prototype]]속성을 설정하는 방법
__proto__
생성자함수.prototype
Object.create(parObj, [descriptors])
생성자함수.prototype방법이 가장 오래된 방법으로 사용되고 있었고 2012년에 Object.create메소드가 지원되어 사용되었지만 여전히 상위객체에 접근하거나 설정하는 방법이 없어 __proto__ 비표준속성을 사용하게 되었다.
그후 2015년에 getPrototypeOf,setPrototypeOf메소드가 추가되었지만 __proto__ 비표준속성이 너무 많은 곳에서 사용되었다.
여기서 의문점이 생긴다.
많이 퍼진 __proto__속성을 표준화하여 사용하면 되지 왜 getPrototypeOf,setPrototypeOf메소드를 추가하였을까?
__proto__속성은 오직 2가지유형(객체 또는 null)의 값만 받을 수 있다. 다른 유형의 값은 무시된다.
let obj = {};
let key = prompt("입력하고자 하는 key는 무엇인가요?", "__proto__");
obj[key] = "...값...";
alert(obj[key]); // "...값..."이 아닌 [object Object]가 출력됩니다.
사용자로부터 값을 입력받아 객체키를 받고 값을 할당하는 경우 키로 __proto__이 입력되면 obj.__proto__에 값을 설정하게된다.
이것은 분명의도치 않은 것이지만 사용자입력값이기때문에 발생한것으로 할당값이 객체가 아닌경우에는 큰문제가 발생하지 않는다.
만약 할당값이 객체라면 예기치않은 치명적인 상황이 발생할 수 있으며 이런 상황은 필히 예방해야한다.
여하튼 __proto__속성을 사용함으로써 발생할 수 있는 상황이며 setPrototypeOf메소드를 사용하면 발생하지 않는다.
이래서 __proto__속성을 사용하지 않는 것이 좋은 것이다.
위의 버그를 피하는 방법
__proto__속성이 상속속성으로 사용되는 것은 Object.prototype객체로부터 상속되기때문이다.
let obj = Object.create(null);
let key = prompt("입력하고자 하는 key는 무엇인가요?", "__proto__");
obj[key] = "...값...";
alert(obj[key]); // "...값..."이 제대로 출력됩니다.
Object.create(null);으로 생성된 객체는 어떠한 프로퍼티도 상속받지 않기때문에 __proto__속성은 고유한 기능의 속성이 없는 것이다.
이렇게 되면 생성객체는 아무 프로퍼티도 없는 단순한 연관배열기능만 하는 순수한 객체가 되는 것이다.
Object.keys, values, entries메소드는 정적메소드이기 때문에 순수객체에도 사용가능하여 연관배열로 사용이 가능하다.
오직 연관배열기능만하는 객체가 필요하다면 순수객체를 사용하는것도 좋다.
보통의 경우에는 객체가 생성될때 상속관계설정이 이루어지고 이후 상속설정이 변경되지 않는다.
__proto__속성이나 setPrototypeOf메소드로 상속관계를 수정하는것은 객체 프로퍼티 접근 관련 최적화를 망치기 때문에 성능에 나쁜 영향을 미친다.