developer tip

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

copycodes 2020. 9. 16. 07:50
반응형

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";
    }
}

If you don’t specify a constructor for a base class, the following definition is used:

constructor() {}

For derived classes, the following default constructor is used:

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

EDIT: Found this on developer.mozilla.org:

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

Source


Just registered to post this solution since the answers here don't satisfy me the least since there is actually a simple way around this. Adjust your class-creation pattern to overwrite your logic in a sub-method while using only the super constructor and forward the constructors arguments to it.

As in you do not create an constructor in your subclasses per se but only reference to an method that is overridden in the respective subclass.

That means you set yourself free from the constructor functionality enforced upon you and refrain to a regular method - that can be overridden and doesn't enforce super() upon you letting yourself the choice if, where and how you want to call super (fully optional) e.g.:

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");

cheers!


You can omit super() in your subclass, if you omit the constructor altogether in your subclass. A 'hidden' default constructor will be included automatically in your subclass. However, if you do include the constructor in your subclass, super() must be called in that constructor.

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

Read this for more information.


I would recommend to use OODK-JS if you intend to develop following OOP concepts.

OODK(function($, _){

var Character  = $.class(function ($, µ, _){

   $.public(function __initialize(){
      $.log('invoke character');
   });
});

var Hero = $.extends(Character).class(function ($, µ, _){

  $.public(function __initialize(){
      $.super.__initialize();
      $.log('invoke hero');
  });
});

var hero = $.new(Hero);
});

The answer by justyourimage is the easiest way, but his example is a little bloated. Here's the generic version:

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();
    }
}

Don't extend the real constructor(), just use the fake _constructor() for the instantiation logic.

Note, this solution makes debugging annoying because you have to step into an extra method for every instantiation.


Try:

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


Simple solution: I think its clear no need for explanation.

class ParentClass() {
    constructor(skipConstructor = false) { // default value is false
        if(skipConstructor) return;
        // code here only gets executed when 'super()' is called with false
    }
}
class SubClass extends ParentClass {
    constructor() {
        super(true) // true for skipping ParentClass's constructor.
        // code
    }
}

참고URL : https://stackoverflow.com/questions/31067368/how-to-extend-a-class-without-having-to-use-super-in-es6

반응형