왕기
30
2017-05-15 17:35:58 작성 2017-05-15 17:36:18 수정됨
6
1328

[JS] [초보] 상속관련 질문


안녕하세요! Udacity 에서 Front end 나노디그리를 수강중인 학생입니다.
상속과 관련해서 궁금한 부분이 있어서 번거로우시겠지만 질문을 드리고자 합니다.

왕초보라 아직 이해가 부족한 부분이 많습니다. 따끔하게 지적해주시면 감사하겠습니다!


Udacity 에서 Front-end(nanodegree) 과정을 수강하고 있는데, instantiate 과 관련한 부분에서 궁금한 점이 생겨 질문드립니다.🤷‍♀️
amy = new Car(1); ben = new van(1); amy.move(); ben.move();
Javascript
위와 같이 Car 과 Van class의 instance인 amyben 이 있습니다. 두 instance의 .move 라는 method 시행하고자 합니다.
Van과 Car의 constructor 는 다음과 같이 정의되어 있습니다.
var Car = function (loc) { this.loc = loc; }; Car.prototype.move = function(){ this.loc++; }; var Van = function(loc){ Car.call(this,loc); };
Javascript
Udacity 에서 설명하는대로라면, 첫 번째 코드 블럭의 3번 째 줄( amy.move) 에서
1.
amy.move() 를 시행한다.
2.
amy 에게는 .move 라는 method가 없다. 실행 실패.
3.
실패한 lookup을 상위(?) 에 있는- 혹은 상속받은(?)- Car.prototype 에서 찾는다.
4.
Car.prototype.move 라는 method를 실행한다. (this = amy)
하지만, Van 의 instance ben.move 가 되지 않습니다. Car.prototype과의 연계되어 있는 부분이 없기 때문일텐데요. (이 부분은 제가 잘못이해한 것이 있을까하여 코드를 설명해 둔 것입니다)
🙋 질문
1.
console.log(ben.loc) 의 값은 잘 나오는데요. Van의 constructor에는 Car.call(this,loc); 한 줄 밖에 없습니다. 이 constructor에서 Return 되는 것이 Car.call 의 Return 값인가요?
2.
그리고 ben.move 가 동작하게 하려면 아래 코드를 추가하면 되는데요, 이 코드는 Best option이 아니라고 합니다.
Van.prototype.__proto__ = Car.prototype;
Javascript
이 코드가 좋지 않은 이유가
퍼포먼스에 영향을 미치는 요소가 있기 때문인가요?
혹은 오류의 가능성이 있어서 일까요?
코드가 명확하지 않기 때문일까요?
엉망인 설명 읽어주셔서 감사합니다 ㅜ 답변 부탁드리겠습니다
0
  • 답변 6

  • LichKing
    16k
    2017-05-15 18:00:55

    1. Car.call의 리턴이 있나요? Van의 constructor가 리턴하는건 new 연산자로 인해 생성된 this 입니다.

    Car의 this 를 치환하기위해 call 메서드에 인자로 전달하는 this가 반환됩니다.


    2. __proto__는 비표준으로 사용을 권장하지 않습니다. 그리고 코드가 사용법도 좀 이상한거같네요. 굳이 __proto__ 에 접근하지않아도 됩니다.

    Van.prototype = Car.prototype 으로 해보세요.

  • 왕기
    30
    2017-05-15 22:36:10

    @LichKing


    친절한 답변 감사드립니다!!!!!
    답변 정말 감사드립니다! 번거로우시겠지만 관련한 다른 궁금증이 생기는데요!

    1. 함수 자체가 Return을 하는게 아니라 New 가 하는 일이었던 거군요!

    결국 new 연산자의 핵심을 간추려본다면 객체 생성후 함수 내부의 this에 생성한 객체를 대입하여 멤버들을 추가하고 그 객체를 반환 하는것이라 볼수있다"
    출처: http://multifrontgarden.tistory.com/69 [우리집앞마당]

    지인분이 new의 개념에 대해 참고하라고 보내주신 링크가 우연찮게도 LichKing님의 포스트인 것 같네요 ㅎㅎ

    2. 비표준이라는게 있군요, 새로운 사실을 알게되었습니다!

    한 가지 궁금해진 것은, 사실 Van은 Car를 상속받아서 새로운 Method 를 추가해야하는 녀석이라 Car와 속성이 완전히 같으면 안되는데요, 

    Van.prototype = Car.prototype 로 정의할때, Van 과 Car 가 다른 속성을 갖는게 어렵거나 하는 문제는 없을지요?

    아래와 같은식으로 추가할 수 있기 때문에 문제 없는 것일까요?

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

    코스에서는 마지막에 아래와 같이 Object.create 을 쓰는 것이 가장 좋은 방법이라고 합니다. 두 방식의 차이가 크게 날까요?

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


    작성해주신 포스트 참고해서 많은 것을 배웠습니다. 그리고 친절한 답변 정말 감사드립니다!


  • 단설
    624
    2017-05-15 23:03:07

    1. 우선 자바스크립트 new 키워드가 어떻게 동작하는지 찾아보시는게 좋겠네요. 자바스크립트에서 새로운 인스턴스를 만들 때 두 가지 방식으로 동작합니다.

    우선 Constructor에 return이 있는 상황입니다. 이 때는 그 return 객체를 새로운 인스턴스로 돌려주게 됩니다. 다른 하나는 return이 없을 때인데요, 이 때는 Constructor.prototype을 진짜 prototype으로 갖는 새로운 객체를 생성하고 이 것을 this로 바인딩한 다음 Constructor를 실행하고 this를 돌려줍니다.

    저 Van이라는 Constructor은 두번째 사례를 따르고 있습니다. new Van()을 하게 되면 Van.prototype을 진짜 prototype으로 갖는 새로운 객체를 생성하고, 그 객체를 this로 바인딩 한 다음에 Car을 호출합니다. 그리고 그 this를 반환하죠. 새로운 객체에 loc라는 변수가 할당되고 반환되는 것입니다.


    2. __proto__는 Webkit 기반 브라우저에서 진짜 prototype을 가리키는 키워드입니다. 진짜 prototype을 가리키는 키워드는 브라우저 구현에 따라 달라질 수 있습니다. 모든 브라우저에서 동작하는 코드를 작성하고싶다면 저런 식으로 코드를 짜서는 안될 일이죠.

    프로토타입 체인 자체는 정상적으로 연결되기 때문에 ben.move()가 정상적으로 동작은 하긴 할겁니다. 단, 웹킷 기반 브라우저에서만요.

    Van.prototype에다가 Car.prototype을 바로 할당해도 되긴 하겠지만.. 아마 저 예제 코드가 보여주고 싶은건 좀 다른 것 같네요. 아마 실제로 프로토타입 체인이 어떻게 이어지는지 보여주고 싶었던 것 같습니다.

    Van.prototype에 그냥 Car.prototype을 할당하게 되면 Van의 진짜 prototype이 그저 Car.prototype이 되어버리니깐요. 위 코드처럼 체이닝하고, 어떤 브라우저에서든 정상적으로 동작하게 만들고 싶다면 Van.prototype = new Car()이 되어야 할 것입니다.

  • 단설
    624
    2017-05-15 23:09:50

    아, 댓글 다는 사이에 추가 댓글이 달려있었네요.

    말하신 대로 Van과 Car의 유의미한 차이점을 만들어내기 위해서 체이닝을 하게 되는 것입니다. 지금 올려주신 코드처럼 그저 Van.prototype = Car.prototype 을 한 다음 Van.prototype.something에 함수를 추가하면 모든 Car 인스턴스에도 동일하게 something 함수가 추가되기 때문에 문제가 발생하죠.

    저는 new Car()이라고 했는데 생각해보니 굳이 Car의 constructor을 거칠 필요 없이 그냥 진짜 prototype만 연결하면 되는 부분이라 Object.create 쓰는게 더 좋아보입니다.

  • LichKing
    16k
    2017-05-16 07:31:25

    아 제 블로그가 이세상 누군가에게는 도움이 되고있었던거같네요 ㅎㅎ;; 링크보고 깜짝놀랐습니다.

    생성자의 return에 대해 좀 더 자세히 말씀드리면 생성자 내에 return이 없으면 new 연산자로 생성된 객체가 반환됩니다. 생성자 내에 return이 명시적으로 존재할 경우 return이 참조타입이면 참조타입이, 기본타입이면 new연산자로 생성된 this가 반환됩니다.


    var Cons1 = function(){
      this.age = 15;
      return {};
    }
    
    var obj1 = new Cons1(); // 명시적 return의 타입이 참조타입이기때문에 new로 생성된 this는 반환되지않고 {}가 반환됩니다.
    
    var Cons2 = function(){
      this.age = 15;
      return 10;
    }
    
    var obj2 = new Cons2(); // 명시적 return의 타입이 기본타입이기때문에 new로 생성된 this가 반환되고 10은 반환되지 않습니다.


    프로토타입 체이닝은 제가 실수했네요 ES5 미만에서는 Van.prototype = new Car(); 로 체이닝을 형성하고 ES5에서는 Object.create를 권장하는걸로 압니다. 윗분께서 잘 달아주셨네요.

  • 왕기
    30
    2017-05-16 15:12:41

    @LichKing, @단설 

    설명 감사드립니다! 이해하는데 큰 도움이 되었습니다!

    답변만 받고 사라지기엔 죄송스러워서 간단히 답변 주신내용을 포스트로 정리해봤습니다.

    https://goo.gl/AoSjzJ

    #정리된 부분 중에서도 오류가 있을 수 있으니 피드백 감사히 받겠습니다!

  • 로그인을 하시면 답변을 등록할 수 있습니다.