[javascript] ES6에서 super를 사용하지 않고 클래스를 확장하는 방법은 무엇입니까?

super부모 클래스를 호출하는 메서드를 호출 하지 않고 ES6에서 클래스를 확장 할 수 있습니까?

편집 : 질문이 오해의 소지가있을 수 있습니다. 우리가 전화해야하는 표준입니까, super()아니면 뭔가 놓치고 있습니까?

예를 들면 :

class Character {
   constructor(){
      console.log('invoke character');
   }
}

class Hero extends Character{
  constructor(){
      super(); // exception thrown here when not called
      console.log('invoke hero');
  }
}

var hero = new Hero();

super()파생 클래스를 호출하지 않을 때 범위 문제가 발생합니다->this is not defined

나는 v2.3.0에서 iojs –harmony로 이것을 실행하고 있습니다.



답변

ES2015 (ES6) 수업의 규칙은 기본적으로 다음과 같습니다.

  1. 자식 클래스 생성자에서 thissuper호출 할 때까지 사용할 수 없습니다 .
  2. ES6 클래스 생성자 super는 하위 클래스 인 경우 호출 해야합니다. 그렇지 않으면 초기화되지 않은 개체를 대신하기 위해 명시 적으로 일부 개체를 반환해야합니다.

이것은 ES2015 사양의 두 가지 중요한 섹션으로 나뉩니다.

섹션 8.1.1.3.4this기능에 무엇이 있는지 결정하는 논리를 정의합니다 . 클래스의 중요한 부분 this"uninitialized"상태에있을 수 있으며이 상태에서 사용하려고 this하면 예외가 발생한다는 것입니다.

9.2.2 , [[Construct]],를 통해 호출되는 함수의 동작을 정의하는 new또는 super. 기본 클래스 생성자를 호출 할 때의 this8 단계에서 초기화 [[Construct]]되지만 다른 모든 경우 this에는 초기화되지 않습니다. 생성이 끝날 때가 GetThisBinding호출되므로 super아직 호출되지 않았거나 (초기화 됨 this) 명시 적 교체 객체가 반환되지 않은 경우 생성자 호출의 마지막 줄에서 예외가 발생합니다.


답변

복수 응답하고 진술 코멘트가 있었다 super 반드시 첫 번째 줄의 내부에 constructor. 그것은 단순히 잘못된 것입니다. @loganfsmyth 답변에는 요구 사항에 대한 필수 참조가 있지만 다음과 같이 요약됩니다.

상속 ( extends) 생성자 super 사용 되지 않더라도 사용 this하기 전과 반환하기 전에 호출 해야합니다.this

을 (를 this) 호출하기 전에 (를 사용하지 않고 ) 명령문을 갖는 것이 합리적 일 수있는 이유를 보려면 아래 부분 (Chrome에서 작동 …)을 참조하십시오 super.

'use strict';
var id = 1;
function idgen() {
  return 'ID:' + id++;
}

class Base {
  constructor(id) {
    this.id = id;
  }

  toString() { return JSON.stringify(this); }
}

class Derived1 extends Base {
  constructor() {
    var anID = idgen() + ':Derived1';
    super(anID);
    this.derivedProp = this.baseProp * 2;
  }
}

alert(new Derived1());


답변

새로운 es6 클래스 구문은 프로토 타입이있는 “이전”es5 “클래스”에 대한 다른 표기법 일뿐입니다. 따라서 프로토 타입 (기본 클래스)을 설정하지 않고 특정 클래스를 인스턴스화 할 수 없습니다.

그것은 치즈를 만들지 않고 샌드위치에 넣는 것과 같습니다. 또한 샌드위치 만들기 전에 치즈 넣을 수 없으니 …

this슈퍼 클래스를 호출하기 전에 키워드를 사용 하는 super()것도 허용되지 않습니다.

// valid: Add cheese after making the sandwich
class CheeseSandwich extend Sandwich {
    constructor() {
        super();
        this.supplement = "Cheese";
    }
}

// invalid: Add cheese before making sandwich
class CheeseSandwich extend Sandwich {
    constructor() {
        this.supplement = "Cheese";
        super();
    }
}

// invalid: Add cheese without making sandwich
class CheeseSandwich extend Sandwich {
    constructor() {
        this.supplement = "Cheese";
    }
}

기본 클래스에 대한 생성자를 지정하지 않으면 다음 정의가 사용됩니다.

constructor() {}

파생 클래스의 경우 다음 기본 생성자가 사용됩니다.

constructor(...args) {
    super(...args);
}

편집 :이 발견 developer.mozilla.org:

When used in a constructor, the super keyword appears alone and must be used before the this keyword can be used.

출처


답변

실제로 이것에 대한 간단한 방법이 있기 때문에 여기에 대한 답변이 나를 만족시키지 못하기 때문에이 솔루션을 게시하도록 등록했습니다. 슈퍼 생성자 만 사용하는 동안 하위 메서드에서 논리를 덮어 쓰고 생성자 인수를 여기에 전달하도록 클래스 생성 패턴을 조정합니다 .

에서와 같이 하위 클래스 자체에 생성자를 만들지 않고 해당 하위 클래스에서 재정의 된 메서드에 대한 참조 만 만듭니다.

즉, 사용자에게 적용되는 생성자 기능에서 자유 로워지고 일반 메서드를 사용 하지 않습니다.이 메서드는 재정의 될 수 있으며 super (완전히 호출하려는 경우)를 선택할 때 super ()를 적용하지 않습니다. 선택 사항) 예 :

super.ObjectConstructor(...)

class Observable {
  constructor() {
    return this.ObjectConstructor(arguments);
  }

  ObjectConstructor(defaultValue, options) {
    this.obj = { type: "Observable" };
    console.log("Observable ObjectConstructor called with arguments: ", arguments);
    console.log("obj is:", this.obj);
    return this.obj;
  }
}

class ArrayObservable extends Observable {
  ObjectConstructor(defaultValue, options, someMoreOptions) {
    this.obj = { type: "ArrayObservable" };
    console.log("ArrayObservable ObjectConstructor called with arguments: ", arguments);
    console.log("obj is:", this.obj);
    return this.obj;
  }
}

class DomainObservable extends ArrayObservable {
  ObjectConstructor(defaultValue, domainName, options, dependent1, dependent2) {
    this.obj = super.ObjectConstructor(defaultValue, options);
    console.log("DomainObservable ObjectConstructor called with arguments: ", arguments);
    console.log("obj is:", this.obj);
    return this.obj;
  }
}

var myBasicObservable = new Observable("Basic Value", "Basic Options");
var myArrayObservable = new ArrayObservable("Array Value", "Array Options", "Some More Array Options");
var myDomainObservable = new DomainObservable("Domain Value", "Domain Name", "Domain Options", "Dependency A", "Depenency B");

건배!


답변

서브 클래스에서 생성자를 모두 생략하면 서브 클래스에서 super ()를 생략 할 수 있습니다. ‘숨겨진’기본 생성자가 하위 클래스에 자동으로 포함됩니다. 그러나 하위 클래스에 생성자를 포함하는 경우 해당 생성자에서 super ()를 호출해야합니다.

class A{
   constructor(){
      this.name = 'hello';
   }
}
class B extends A{
   constructor(){
      // console.log(this.name); // ReferenceError
      super();
      console.log(this.name);
   }
}
class C extends B{}  // see? no super(). no constructor()

var x = new B; // hello
var y = new C; // hello

읽기 자세한 내용은.


답변

justyourimage의 대답은 가장 쉬운 방법이지만 그의 예는 약간 부풀어 있습니다. 다음은 일반 버전입니다.

class Base {
    constructor(){
        return this._constructor(...arguments);
    }

    _constructor(){
        // just use this as the constructor, no super() restrictions
    }
}

class Ext extends Base {
    _constructor(){ // _constructor is automatically called, like the real constructor
        this.is = "easy"; // no need to call super();
    }
}

실제를 확장하지 말고 인스턴스화 논리에 constructor()가짜 _constructor()를 사용하십시오 .

이 솔루션은 모든 인스턴스화에 대해 추가 메서드를 실행해야하기 때문에 디버깅을 성가 시게 만듭니다.


답변

시험:

class Character {
   constructor(){
     if(Object.getPrototypeOf(this) === Character.prototype){
       console.log('invoke character');
     }
   }
}


class Hero extends Character{
  constructor(){
      super(); // throws exception when not called
      console.log('invoke hero');
  }
}
var hero = new Hero();

console.log('now let\'s invoke Character');
var char = new Character();

Demo