1. 프로토타입 기반 언어란?
javaScript는 프로토타입 기반 언어(prototype-based language)라 불립니다.
모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미입니다.
프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수 있고 그 상위 프로토타입 객체도 마찬가지입니다.
이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간입니다.
정확히 말하자면 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있습니다.
javaScript는 java와 달리 class가 없었습니다.
대신 프로토타입 객체를 참조하여, 객체를 생성합니다.
(하지만 ES6에서 class가 추가되어 class로 객체를 생성할 수 있습니다.)
2. 프로토타입 객체란?
프로토타입 객체는 자신이 다른 객체의 원형이 되는 객체입니다. 모든 객체는 프로토 타입에 접근할 수 있습니다.
프로토타입 객체도 동적으로 런타임에 멤버를 추가할 수 있습니다.
같은 원형을 복사로 생성된 모든 객체는 추가된 멤버를 사용할 수 있습니다.
function Test() {};
var t1 = new Test();
var t2 = new Test();
Test.prototype.name = "테스트";
Test.prototype.getName = function() {
return "함수 테스트";
};
console.log(t1.name); // 테스트
console.log(t1.getName()); // 함수 테스트
console.log(t2.name); // 테스트
console.log(t2.getName()); // 함수 테스트
3. 객체 생성 방법과 차이점
1) 생성자를 이용한 객체 생성 (classcal 방식)
new 연산자를 이용해서 함수를 호출해서 객체를 만드는 방식입니다.
function Test1() {
this.a = 1;
this.b = 2;
this.getSum = function() {
return this.a + this.b;
}
}
var t1 = new Test1();
console.log(t1); // 아래 이미지 참조
console.log(t1.getSum()); // 3
new 연산자로 인스턴스를 생성한 경우 함수형태로 객체를 선언해야합니다.
또한 함수인자로 내부 객체의 값을 설정할 수 있습니다.
var t1 = new test1(a, b); 와 같은 방법으로 파라미터를 넘겨 내부 객체의 값을 설정할 수 있습니다.
프로토타입 수정하기
function Test1() {
this.a = 1;
this.b = 2;
this.getSum = function() {
return this.a + this.b;
}
}
var t1 = new Test1();
// 인스턴스 추가
test1.prototype.c = 10;
test1.prototype.setA = function(param) {
this.a = param;
}
console.log(t1); // 이미지 참조
t1과 같이 객체를 생성한 후에 인스턴스나 메소드를 추가해도 t1으로 새로 추가된 인스턴스나 메소드를 호출할 수 있습니다. 하지만 반대로 생성한 t1객체에서 t1.d = 20; 과 같이 인스턴스를 추가해도 프로토타입 객체인 test1()에는 추가되지 않습니다(undefined).
중요!! 프로토타입에 선언하지 않고 일반 객체 수정 방식(t1.d = 20)으로하면 인스턴스 객체에 나타나지 않습니다. 프로토타입으로 선언해야 인스턴스 객체의 __proto__에 속성이나 메소드가 추가됩니다.
2) Object.create() 메소드를 이용한 객체 생성 (prototypal 방식)
ECMAScript5에 도입된 객체를 만드는 새로운 방식입니다.
// 리터럴 표기를 이용한 객체의 생성
var test2 = {
a : 3,
b : 4,
getSum : function() {
return this.a + this.b;
}
}
var t2 = Object.create(test2);
console.log(t2); // 이미지 참조
console.log(t2.getSum()); // 7
t2.a = 7;
console.log(t2.getSum()); //11
이와 같은 prototypal 방식은 classcal 방식과 마찬가지로 프로토타입 객체의 메소드와 속성을 상속받는다.
하지만 prototypal 방식은 __proto__(proto 비표준) 속성에 원형 프로토타입 객체를 숨은 링크로 참조합니다.
__proto__는 프로토타입 체인으로 부모 객체와 연결됩니다.
또한 Object.create() 방식은 원형 프로토타입 객체나 만들어진 객체의 프로토타입에 접근하지 않아도 간편한게 속성(인스턴스)를 수정할 수 있습니다.
그리고 new 연산자를 사용해서 객체를 생성할 경우는 항상 생성자(constructor)를 만들어 줍니다.
하지만 Object.create 메소드로 생성한 객체는 생성자(constructor)를 만들지 않는 경우가 있습니다.
위 그림과 같이 함수를 이용하여 Object.create() 메소드로 객체를 생성할 경우 생성자를 만들지 않습니다.
이는 Object.create() 메소드로 객체를 생성하여 불필요한 생성자를 만들지 않는다는 특징이 있지만, 하위 계층의 객체를 계속해서 생성해서 상위 메소드를 상속할 경우 문제가 발생합니다.
이 경우 생성자는 직접 생성해주는 코드를 넣어작성하셔야합니다.
함수를 이용하여 Object.create() 메소드로 객체를 생성하는 경우에 대해서는 다음 글에서 좀 더 자세히 다루겠습니다.
ES6에 class문법이 등장해서 prototype으로 속성, 메소드를 추가하지 않고 class 하나로 속성과 메소드를 추가하는 방식을 사용하게 되었다.
class 등장 이후 prototype으로 추가하는 방식은 많이 쓰이지 않지만, 내부 메카니즘이 같기 때문에 prototype 체인닝을 이해할 필요가 있습니다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
https://www.nextree.co.kr/p7323/
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes
'javaScript' 카테고리의 다른 글
javaScript - 비동기 함수 동기식으로 실행하기(Promise와 async) (0) | 2021.07.12 |
---|---|
javaScript - 스프레드 오퍼레이터(Spread Operator) (0) | 2021.07.12 |
javaScript - 유용한 메소드 모음 (0) | 2021.07.07 |
javaScript - 객체 생성 class (0) | 2021.07.05 |
javaScript - 객체 생성 Object.create() (0) | 2021.07.01 |
댓글