자바스크립트는 일반함수와 생성자함수의 기술적구분이 없으며 모든 함수는 생성될때 상속을위한 prototype일반속성이 추가되고 빈객체를 만들어 참조설정한다고 했다.
생성자함수.prototype = 객체;
객체.constructor = 생성자함수;
이러한 참조를 순환참조라고 한다.
순환참조하게되면 어느한쪽 속성이 null이 되어도 객체는 가비지콜렉션대상이 되지않는다.(실수로 소멸되는것을 방지)
new 생성자함수로 객체가 생성되면 객체[[prototype]]숨김속성에 생성자함수.prototype객체가 참조할당된다고 했다.
new Array();로 생성된 배열은 Array.prototype객체를 상속받아야 배열메소드를 사용할 수 있다.
new Object();로 생성된 객체는 사용자정의객체를 만들기위한 목적이 대부분이므로 객체생성후 상위객체를 변경한다.
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let a1 = new Rabbit('rat');
Rabbit.prototype = animal; 이렇게 하면 생성되는 객체들은 animal와 상속관계가 형성된다.
만약
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
let a1 = new Rabbit('rat');
a1.__proto__ =animal;
이와같이 객체생성후 상속관계를 변경하는 것은 엔진 입장에서 큰 부하가 발생되는 과정이기때문에 불필요한 객체상속속성을 변경하는것은 하지 않는것이 좋다.
Rabbit.prototype = animal;와 같이 생성자함수속성에 설정후 객체를 생성하면 생성과 동시에 상속관계를 형성하게 된다.
생성자함수는 생성객체들이 가져야할 프로퍼티를 정의하는 수단일뿐아니라 상속속성도 설정한다.
function Rabbit() {}
let rabbit = new Rabbit();
console.log(rabbit.constructor); // Rabbit
Rabbit.prototype객체에 constructor속성이 있으며 Rabbit이 할당되어있다고 했는데 rabbit.constructor도 Rabbit이 출력되네???
왜 그럴까?
언어에서 그냥 서비스로 해주는건 아닐까? 그런일은 절대로 없다.
그럴수 밖에 없으니 그렇게 되는것이다.
rabbit객체는 Rabbit.prototype객체를 상속하는가? 당연히 그렇지.
자바스크립트는 constructor값을 보장하지 않는다
new 생성자함수가 호출되면 constructor속성을 가진 객체를 만들고 순환참조까지 한다고 했다.
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let a1 = new Rabbit('rat');
console.log(a1.constructor); // Object
Rabbit.prototype = animal;
대부분의 일에는 크던 작던 부작용이 발생하는 경우가 많다.
위코드가 수행되었을때 어떤 부작용이 발생하는가?
Rabbit.prototype객체의 constructor값에는 Rabbit함수가 참조할당되어있었는데 animal의 constructor속성으로 대체된다.
animal객체에는 자신의 constructor속성은 없지만 상위객체 즉 Object.prototype객체의 constructor값에 Object함수가 참조할당되어있다.
따라서 Rabbit.prototype.constructor에는 Object생성자함수가 설정된다.
만약 new Rabbit.prototype.constructor();으로 객체를 생성하면 new Object();로 객체를 생성하게 되는 것이다.
따라서 자바스크립트는 constructor값을 보장하지 않는다라고 한것이다.
constructor속성을 잃지않기위해 아래와같이 할수도 있는데 Object.assign(Rabbit.prototype,animal); 이방법은 Rabbit생성자함수로부터 생성되는 객체와 animal객체의 상속관계를 형성하는 것이 아니고 Rabbit.prototype객체에 상속받을 속성을 추가하는것에 지나지 않는다. 따라서 animal객체의 속성을 변경을때 반영되지 않는다.
설정된 속성값은 사용자가 변경하지 않는한 변경되지 않는다
function Rabbit() {
}
Rabbit.prototype = {
eats: true
};
let rabbit = new Rabbit();
Rabbit.prototype = {};
console.log( rabbit.eats ); // true
function Rabbit() {}
Rabbit.prototype = {
eats: true
};
let rabbit = new Rabbit();
위코드는 rabbit[[prototype]]={ eats: true };
사용자가 __proto__와 동등한 문법으로 변경하지 않는한 원객체를 참조한다.
객체생성이후에 Rabbit.prototype={};으로 생성자함수의 prototype속성을 변경했다고해서 기존에 생성된 객체의 [[prototype]]속성이 변경된다는 것은 있을 수 없는 것이다.
생성된 객체가 수백개면 변경될때마다 엔진이 객체 속성값을 일일히 변경한다는 것은 말이 되지 않는 것이다.
혼동을 유발하는 것이 있다.
Rabbit.prototype ={eats: true};일때 속성이 추가되는 경우라면 속성이 추가되기 이전 생성된 객체라도 추가된 속성을 자기속성처럼 사용가능하다.
이것은 당연한 것이 어떤 속성에 접근하려고할때 바로전에 추가되어있다면 접근하는데 전혀 문제가 되지 않는다는 것이다.