본문 바로가기
JavaScript/JavaScript

Javascript) 생성자함수 - prototype, __proto__, 속성비교

by 박채니 2022. 5. 26.

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


생성자함수 - prototype

- javascript는 prototype 기반의 상속 모델을 가진 객체 지향 언어

- 생성자 함수 호출로 생성된 객체는 prototype과 연결된 prototype 체인을 가짐 (prototype 객체를 부모로 삼음)

- prototype체인의 최상위에는 Object.prototype이 존재

 

HTML 코드

<button onclick="test3();">생성자함수 - prototype</button>

 

Javascript 코드

const test3 = () => {
    console.log(Duck);  // 생성자함수
    console.log(Duck.prototype) // prototype

};

function Duck(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
};

Duck.prototype.say = function() {
    console.log(`안녕하세요, ${this.firstName} ${this.lastName}입니다.`);
};

Duck을 호출하면 생성한 함수가 출력됩니다.

Duck.prototype을 호출하면 constructor가 있는데 constructor는 생성자 함수를 링크하고 있는 것을 확인할 수 있습니다.

constructor 안에 prototype을 열어보면 Duck.prototype이 링크 되어있는 것을 확인할 수 있습니다.

 

이로써, Duck은 prototype을 갖고 있고, Duck.prototype은 constructor를 갖고 있어 서로 참조 하고 있다는 것을 알 수 있습니다.

 

console.log(Duck.prototype.constructor == Duck);

Duck.prototype의 constructor가 생성자 함수를 링크하고 있었고, 이를 비교하니 true가 나왔습니다.

 

 

객체 생성

const lee = new Duck('이', '오리'); // duck 객체
lee.say();
console.log(lee);

Duck 생성자 함수를 이용하여 lee 객체를 생성해보았습니다.

Duck.prototype에 링크해뒀던 say()메소드가 잘 출력되고, prototype이 Duck.prototype이라는 것을 알 수 있습니다.

 

Duck 생성자함수를 통해서 객체를 생성 (new Duck())하였지만 새로 생성된 객체 lee는 Duck을 부모로 삼지 않고 Duck.prototype을 부모로 삼습니다.

따라서 Duck.prototype에 링크 되어있는 say()를 사용할 수 있는 것이죠.

 

 

toString() 메소드 호출

console.log(lee.toString());
console.log(`${lee}`);

위 구조를 보았을 때, 그리고 Duck.prototype에 toString()메소드를 선언한 적이 없는데 오류가 나지 않고 잘 출력되는 것을 확인할 수 있습니다.

이는 최상위 부모인 Object.prototype에 링크 되어있는 메소드이기 때문이죠.

lee에서 toString()메소드를 찾고, 없으니 부모 객체인 Duck.prototype에서 메소드를 찾고, 이마저도 없으니 최상위 부모인 Object.prototype에서 메소드를 찾아내는 것입니다.

 

Object에 링크 되어있는 메소드들

toString() 메소드를 여기서 꺼내와 사용한 것이죠.

 

 

__proto__

- 새로운 객체를 생성한 객체의 prototype 호출

console.log(lee.__proto__); // Duck.prototype 호출
console.log(lee.__proto__ == Duck.prototype);

Duck.prototype을 통해서 Duck의 prototype객체에 접근할 수 있고, lee.__proto__를 통해서도 Duck의 prototype객체에 접근할 수 있습니다.

 

 

생성자 함수는 반드시 new 연산자를 통해 호출

const donald = Duck('Donald', 'Trump');
console.log(donald);

function Duck(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
};

donald에는 undefined가 들어있는 것을 확인할 수 있는데 Duck객체에 리턴 값이 없기 때문입니다.

그렇다면 입력한 'Donald'와 'Trump'는 어떻게 된 걸까요?

 

일반 함수에서 this는 window를 의미합니다. 따라서 매개인자로 넘겨준 'Donald'와 'Trump'는 window의 firstName, window의 lastName에 대입 된 것이죠.

따라서 반드시 생성자 함수는 new 연산자를 통해서 호출해줘야 합니다.

 


속성비교

 

생성자 함수

function A() {
    this.username = '알 파치노';
    this.hello = function() {
        console.log('안녕 알파치노');
    };
};

 

생성 객체 속성 호출

const test4 = () => {
    const a = new A();

    console.log(a);
    console.log(a.username);
    a.hello();
}

생성자 함수의 this는 현재 객체이기 때문에 new 연산자를 사용해 생성자 함수 A()의 객체를 만들었다면,

username = '알 파치노'와 hello()는 a 객체 내부에 링크됩니다.

(A 생성자함수 내부가 아님!!!)

 

 

생성자 함수 속성 생성

A.username = '홍길동';
A.hello = function () {
    console.log('안녕 난 홍길동');
};

 

생성자 함수 속성 호출

console.log(A.username);
A.hello();

생성자 함수의 속성 생성 및 호출을 해주었습니다.

'홍길동'과 '안녕 난 홍길동'은 A 객체 내부에 링크 됩니다.

 

 

프로토타입 속성 생성

A.prototype.username = '아이언맨';
A.prototype.hello = function() {
    console.log('안녕 아이언맨');
};

 

프로토타입 속성 호출 (자식 객체 속성은 주석)

console.log(A.prototype.username);
A.prototype.hello();