본문 바로가기

Language/JS Flow

[JS Flow] prototype

 

 

자바스크립트가 어려운 이유는.. 8할이 프로토타입 때문이라고....

자바의 클래스 역할을 하는 프로토타입..! 최대한 이해해서 정리했다.

 

생성자 constructor의 프로퍼티는 prototype, 생성자 instance의 프로퍼티는 __proto__

생성자가 인스턴스를 만들면, 생성자의 프로퍼티인 프로토타입이 __proto__에 참조를 전달한다.

그런데 인스턴트뒤의 __proto__는 생략이 가능하다.

 

그래서 프로토타입이 인스턴스를 바라보고 있는것처럼 보인다.

인스턴스가 프로토타입의 메소드를 마치 자신의 것처럼 갖다쓸수 있다는것..

 

예를 들어보자.

Array라는 생성자로 만든 인스턴스 [1,2,3] 이 있다.

Array에는 프로토타입 말고도 여러가지 프로퍼티를 가지고 있다.

이중에서 prototype만 알아보자면..!

Array.prototype을 이용해 concat(), filter()등의 메소드를 사용할 수 있다.

__proto__가 생략되어, 프로토타입은 Array의 객체를 바라보고 있는것과 마찬가지 이므로

Array의 객체는 [1,2,3].concat() 이런식으로 바로 가져다 쓸 수 있다는것!!

이게 프로토타입의 본질이다.

 

 

 

프로토타입에 접근하는 방법


✔ [CONSTRUNCTOR].prototype

✔ [instance].__proto__

✔ [instance]

모두 프로토타입에 접근해서 프로퍼티를 사용할 수 있는 방법이다.

음... 그냥 써놓으니까 영어 나부랭이같다.

 

CONSTRUNCTOR ==> Person,  instance ==> kim으로 예를 들어보자.

function Person(name, first, second) {
    this.name = name;
    this.first = first;
    this.second = second;
}

 

Person 생성자를 만들면 prototype 프로퍼티가 존재하고 이 prototype객체를 가리킨다.

prototype객체에는 생성자 프로퍼티가 존재하고 Person생성자를 가리킨다. 서로 상호참조 하는것이다.

 

function Person(name, first, second) {
    this.name = name;
    this.first = first;
    this.second = second;
}

Person.prototype.sum = function() {}

Person의 prototype 객체에 함수를 정의한다면 객체안에 생성되는것을 볼 수 있다.

 

function Person(name, first, second) {
    this.name = name;
    this.first = first;
    this.second = second;
}

Person.prototype.sum = function() {}

var kim = new Person('kim',10,20);

생성자의 객체를 생성하면 자동으로 __proto__라는 프로퍼티가 생성되고

__proto__는 prototype객체를 가리키는 것을 볼 수 있다.

 

그래! 이제 여기서!!

console.log(kim.name)

kim.sum()

kim.name을 콘솔에 출력하기 위해서 kim객체를 본다. name이 있네? 출력한다.

kim.sum()을 실행하기 위해 kim 객체를 본다. sum함수가 없다. 이때 __proto__프로퍼티로 prototype객체를 참조한다. sum함수를 가져다쓴다!

이것이 __proto__와 prototype이 존재하는 이유다.

 

 

 

메소드 상속 및 동작 원리


 

function Person(n, a) {
    this.name = n;
    this.age = a;
}

var gomu = new Person('고무곰', 30);
var iu = new Person('아이유', 25);

gomu.setOlder = function() {
    this.age += 1;
}
gomu.getAge = function() {
    return this.age;
}
iu.setOlder = function() {
    this.age += 1;
}
iu.getAge = function() {
    return this.age;
}

gomu, iu 객체를 만들고, 각 객체의 getOlder, getAge라는 메소드를 만들었다.

그런데 gomu의 메소드와 iu의 메소드가 똑같다.

반복을 줄이고 싶어서 코드를 바꿨다.

 

function Person(n, a) {
    this.name = n;
    this.age = a;
}
Person.prototype.setOlder = function() {
    this.age += 1;
}
Person.prototype.getAge = function() {
    return this.age;
}

var gomu = new Person('고무곰', 30);
var iu = new Person('아이유', 25);

생성자의 prototype에 메소드를 넣으면,

생성자의 인스턴스들은 자기것처럼 이 메소드를 사용할 수 있다는것~~!

ex) gomu.setOlder();

인스턴스가 굳이 안들고 있어도 되는 메소드를 생성자가 들게 만든것이다.

 

여기서 의문점은❓ 생성자안에 메소드를 정의하면 되지 않느냐~!

생성자 함수안에 메소드를 정의하면, 객체가 생성될때마다 해당 객체의 메소드를 만들어 메모리에 할당해야한다.

하지만 생성자의 바깥, 즉 생성자의 프로토타입에 정의하면 다른 모든 객체들이 참조하여 사용할 수 있고,

메소드의 재정의가 필요한 객체들은 상황에 맞게 자신만 사용가능한 메소드를 재정의 할 수 있다!

프로토타입으로 인해 메모리의 효율적 사용이 가능하고 유지보수가 쉬워진다.

 

 

 

 

 

'Language > JS Flow' 카테고리의 다른 글

[JS Flow] 클로저(closure)  (0) 2020.04.20
[JS Flow] this  (0) 2020.04.18
[JS Flow] callback함수  (0) 2020.04.18
[JS Flow] 실행 컨텍스트 (hoisting, scope chain)  (0) 2020.04.17
[JS Flow] 데이터 타입  (0) 2020.04.17