누가 이런 질문을 올려주셨다.
function grandfather() {}
grandfather.prototype.name = '홍길동'
function father(){}
father.prototype = new grandfather();
father.prototype.here = 'here father'
function me(){}
me.prototype = new father();
me.prototype.here = 'here me'
console.dir(me) 에서 제가 생각하는 출력 값은
[[prototype]] : father
이 한번은 나오는 것 인데 이렇게 나오지 않고[[prototype]]: grandfather
이 두번 나옵니다. 왜 그런건가요?
원래 자바스크립트를 하지도 않지만, 왜 이런지 흥미가 생겨 원리를 찾아보게 되었다.
각 prototype을 대표하는 (나타내는)값은 prototype.constructor (생성자함수)가 된다.
father의 prototype.construcotr도, me의 prototype.constructor도, 모두 grandfather() {}이 되기 때문에 prototype:grandfather이 2번 나타난다.
먼저 전체 코드를 분석하기 전에,
생성자함수(=f)/프로토타입 객체(=P)/인스턴스 객체(=I)의 관계에 대해 먼저 알고 넘어가자.
이 점을 생각하면서, 아래의 코드에서 일어나는 일을= 분석해보자.
function grandfather() {} // 요소1. 생성자 함수
grandfather.prototype.name = '홍길동' // 요소2. 프로토타입 객체
const g = new grandfather(); // 요소3. 인스턴스 객체
console.log(grandfather.prototype); // {name: 홍길동}
console.log(grandfather.prototype.constructor) // [Function: grandfather]
console.log(g.__proto__) // {name: 홍길동}
console.log(g.constructor) // [Function: grandfather]
function grandfather() {}
선언
grandfather.prototype.name = 홍길동
const g = new gradnefather()
여기까지만 보면, f 와 P의 관계가 꽤 명확해 보인다.
여기서 명심해야 할 점은, I 와 P의 관계이다.
예를 들면, I.name을 호출할 때에는, 동작원리가 꽤 명확해 보인다.
- I에서 'name' 프로퍼티를 찾을 때에는, 먼저 자기 자신에서 찾는다.
- 없으면 I.prototype에 가서 찾게 된다.
- 따라서 I.name = I.prototype.name = P.name = '홍길동'이 된다.
그렇다면 I 의 생성자 함수(=f)를 찾는 것은 어떻게 하는 것일까?
바로 I.constructor가 가리키는 함수를 찾아가면 되는 것이다.
이 원리는 바로 위에서 name을 찾을 때와 똑같은 원리로 동작한다.
constructor 또한 I 자체에 선언된 것이 아니고, I.prototype.constructor를 찾는 일이다.
그렇다면 function father()을 선언하고, father함수의 프로토타입을 지정하면 무슨일이 일어날까?
function grandfather() {} // 요소1. 생성자 함수
grandfather.prototype.name = '홍길동' // 요소2. 프로토타입 객체
// const g = new grandfather(); // 요소3. 인스턴스 객체
function father(){} // 요소4. 생성자함수 2
father.prototype = new grandfather(); // 요소5. 생성자함수2.프로토타입 = 요소3.인스턴스 객체
console.log(father.prototype) // grandfather {}
console.log(father.prototype.constructor) // [Function: grandfather])
이는 prototype 자체는 이름없는 객체라고 볼 수 있기 때문에, 생성자함수(constructor)를 가리키게 되는 상황에서 발생하는 일이라고 볼 수 있겠다.
따라서, father.prototype의 생성자 함수는 father()이 아닌 grandfather()이 된다.
function grandfather() {} // 요소1. 생성자 함수
grandfather.prototype.name2 = '홍길동' // 요소2. 프로토타입 객체
const g = new grandfather(); // 요소3. 인스턴스 객체
function father(){}
father.prototype = new grandfather();
father.prototype.here = 'here father';
const f = new father();
console.log(grandfather.name2)
// grandfather - 프로토타입에 선언한 프로퍼티는 생성자함수에 영향을 주지 않는다.
console.log(grandfather.here)
// undefined - 인스턴스객체에 선언한 프로퍼티는 생성자함수에 영향을 주지 않는다.
console.log(g.name2)
// 홍길동 - 프로토타입에 선언한 프로퍼티는, 인스턴스 객체에 영향을 준다.
console.log(g.here)
// 인스턴스 객체에 선언한 프로퍼티는 프로토타입객체에 영향을 주지 않는다.
console.log(father.name2) // father
console.log(father.here) // undefined
console.log(f.name2) // 홍길동
console.log(f.here) // fatherhere
프로토타입에 선언한 프로퍼티 name2/here은, 모두 생성자함수에서는 그 값을 찾지 못하고, 객체 인스턴스에서만 그 프로퍼티를 찾을 수 있는 것으로 보인다.
그렇다면, 생성자함수에 프로퍼티를 넣어주면, 이 친구들은 값을 어떻게 찾게될까?
재미로 테스트해봤다. 결과를 공유한다.
function grandfather() {
this.age = 60
}
const g = new grandfather();
function father(){
this.age2 = 30
}
father.prototype = new grandfather();
const f = new father();
console.log(grandfather.age) // undefined
console.log(grandfather.age2) // undefined
console.log(g.age) // 60
console.log(g.age2) // undefined
console.log(father.age) // undefined
console.log(father.age2) // undefined
console.log(f.age) // 60
console.log(f.age2) // 30
결론적으로 말하면