JS 상속과 `New` 키워드에 대한 이해

New와 상속에 대한 질문과 답

May 16, 2017 - 4 minute read -
js inheritances

new 키워드로 함수를 호출하는 방법과 상속을 정의하는 법에 대한 질문을 아래와 같이 남겼고, 많은 분들이 도움을 주셨습니다. 도움 받은 만큼, 알게된 내용을 간단히 정리해봤습니다.

🙋 질문 코드

Run.js

amy = new Car(1);
ben = new van(1);
amy.move();
ben.move();

Definition.js

var Car = function (loc) {
	this.loc = loc;
};
Car.prototype.move = function(){
	this.loc++;
};

var Van = function(loc){
	Car.call(this,loc);
};

🙋 질문

  1. 두 번째 코드블럭에서 정의된 Van constructor에서 Return 되는 것이 Car.call 의 Return 값인가요?
  2. 그리고 ben.move 가 동작하게 하려면 아래 코드를 추가하면 되는데요, 이 코드는 Best option이 아니라고 합니다. 이 코드가 좋지 않은 이유가 무엇인가요?
Van.prototype.__proto__ = Car.prototype;

  1. Car.call 의 Return 값이 아니다.
    • new 키워드를 이용해서 함수를 호출하는 경우, 함수 자체가 bind 된 Constructor 속성을 가진 this 값이 Return 된다.
    • (참고)Car.call 은 Van 생성자에서 부모 생성자를 실행하는 라인
  2. 좋지 않은 코드다.
    • [[Prototype]] (__proto__) 속성의 변경은 최신 자바스크립트 엔진의 최적화 방식에 의해 매우 느린 방식” (Facebook의 박철현 님 답변)
    • __proto__ 는 Webkit 기반 브라우저에서 진짜 prototype을 가리키는 키워드입니다” (Okky, 단설 님 답변) 즉 Webkit 기반이 아닌 브라우저에서도 동작하게 하려면 권장되지 않는다. (ECMA 2015 에서 표준으로 지정됨)

상속을 정의하는 방법

자바스크립트는 클래스라는 개념이 없고, 객체를 복사하여(cloning) 새로운 객체를 생성하는 프로토타입 기반의 언어다. (Nextree, 2014).

2번의 질문에서 잘못된 상속을 해결하는 방법은 아래 방법들이 있다. (Nextree 포스팅 참조)

1.Prototype 을 공유하는 방법

var Van.prototype = Car.prototype

Van.prototype.something = function(){
};

이렇게 Prototype 을 정의하는 경우 Car 과 van은 같은 Prototype을 공유하게된다. 즉 아래와 같이 Van.prototype.something 을 추가하는 경우 모든 Car instance 에도 같은 함수를 추가하게 된다. 따라서 목적에 부합하지 않는다. (Okky, 단설 님 답변)

2.new 키워드를 이용해 함수를 호출하는 방법

Van.prototype = new Car();
ben = new Van(3);

Prototype을 위와 같이 정의 하는 경우, Car 을 생성할 때 필요한 loc 파라미터가 Van 의 생성과정에 적용될 수 없다. 따라서 Parameter 가 필요한 객체 생성에 적합하지 않다.

3.apply 함수를 이용해 생정자를 빌려쓰는 법.

var Van = function Van(loc){
 Car.apply(this, arguments);
};

위와 같이 apply 함수를 이용해 Van 을 정의하는 경우, Van의 instance ben 은, 2번의 경우와 달리 loc 값은 전달이 되지만 .move 를 사용할 수 없다. 이유는 Car.prototype 과의 연결이 이뤄지지 않기 때문.

4.Prototypal 한 방식 💯

객체 생성과 동시에 프로토타입객체를 지정합니다.

  • 첫 번째 변수는 부모객체로 사용할 객체( Car.prototype )
  • 두 번쨰 변수는 상속될 개체의 속성에 추가
var Van = function (loc) {
 Car.call(this,loc);
};

Van.prototype= Object.create(Car.prototype);
// Object.create

이렇게 하면 객체 생성, 상속까지 문제 없이 이뤄진다.


(참고) #2 와 관련하여 Return 에 대한 이해

new 키워드와 함께 함수가 호출될 때, 명시적 Return 타입(Return 값이 정의된 경우)에 따라 Return 되는 값이 달라진다. (Okky의 RIchiKing 님 답변)

var Const1 = function(){
	this.age = 15;
	return {};
}

var obj1 = new Const1();
console.log(obj1); // {}
// Const1의 명시적 Return 값은 {}, 즉 참조(Reference) 타입이다.
// {} 가 Return 된다.
// Const2의 명시적 Return 값은 10, 즉 기본(Primitive) 타입이다.
// New 로 생성된 객체(!) 가 Return 된다.

var Const2 = function(){
	this.age = 15;
	return 10;
}

var obj2 = new Const2();
console.log(obj2); // {age:15}

질문을 올린 곳

References

Nextree. 2014. “JavaScript : 프로토타입(prototype) 이해”. Retrieved from http://www.nextree.co.kr/p7323

LichKing, 2015. “#06. JavaScript의 new 와 생성자함수”. Retrieved from http://multifrontgarden.tistory.com/69

❓Inheritances 관련 질문 - 전문