12.2.2 ECMAScript 6 클래스 생성(ECMAScript 6 class generation)

12.2.2 ECMAScript 6 클래스 생성(ECMAScript 6 class generation)

since Haxe 4.0

Haxe 4.0부터 Haxe는 기존의 함수+프로토타입(function+prototype) 조합 대신 ES6 클래스 정의를 생성할 수 있습니다. 이는 제3자 ES6 라이브러리를 사용할 때 필요할 수 있는데, 네이티브 ES6 클래스는 예전 방식으로는 확장할 수 없기 때문입니다.

ES6 생성 모드를 활성화하려면 컴파일러 인자에 -D js-es=6을 추가하기만 하면 됩니다.

super 생성자를 호출하기 전에 this에 접근하기(Accessing this before calling super constructors)

Haxe 클래스와 ES6 클래스 사이의 중요한 차이점 중 하나는 상속이 사용될 때 드러납니다. ES6는 자식 클래스 생성자 안에서 super()를 호출하기 전에는 어떤 방식으로든 this에 접근하는 것을 허용하지 않지만, Haxe는 생성자의 어느 위치에서든 super() 호출을 허용합니다.

Haxe 코드에서 super() 앞에 명시적으로 this에 접근하지 않더라도, 클래스에 초기화 값이 있는 필드가 있다면 이런 상황이 여전히 발생할 수 있습니다.

다음 예를 살펴봅시다:

class Base {
  function new() {
    init();
  }
  function init() {
    trace("base init");
  }
}

class Child extends Base {
  var field = "hello";

  override function init() {
    trace(field);
  }
}

Haxe는 어떤 생성자 코드가 실행되기 전에 필드가 초기화되는 것을 보장합니다. 그리고 ES6에서는 (필드 값을 설정하기 위한) this 접근이 super() 호출 앞에 허용되지 않기 때문에, Haxe는 다음과 같은 예처럼 생성자를 변환하여 이 제약을 우회해야 합니다:

class Base {
  constructor() {
    if(Base._hx_skip_constructor) {
      return;
    }
    this._hx_constructor();
  }
  _hx_constructor() {
    this.init();
  }
  init() {
    console.log("src/Main.hx:6:","base init");
  }
}
class Child extends Base {
  constructor() {
    Base._hx_skip_constructor = true;
    super();
    Base._hx_skip_constructor = false;
    this._hx_constructor();
  }
  _hx_constructor() {
    this.field = "hello";
    super._hx_constructor();
  }
  init() {
    console.log("src/Main.hx:14:",this.field);
  }
}
Base._hx_skip_constructor = false;

컴파일러는 최선을 다해 이 우회 코드를 필요한 경우에만 생성하도록 똑똑하게 동작한다는 점을 참고하세요.

생성자를 가진 extern 클래스 확장(When extending extern classes with constructors)

명심해야 할 중요한 제약 하나는, extern 클래스 구현에는 Haxe가 이런 변환을 수행하는 것이 분명히 불가능하다는 점입니다. 그렇기 때문에 네이티브 extern 클래스를 확장할 때는 super()를 호출하기 전에 this에 전혀 접근할 수 없습니다. Haxe는 이런 경우를 감지하여 this 접근을 요구하는 첫 번째 식 또는 필드 선언을 가리키는 컴파일 오류를 발생시킵니다.

예를 들어:

extern class Base {
  function new();
}

class Child extends Base {
  var field = "hello";
}

이것을 컴파일하려고 하면 다음 오류와 함께 실패합니다: Main.hx:6: characters 3-23 : Must call super() constructor before accessing this in classes derived from an extern class with constructor

하지만 부모 extern 클래스에 생성자가 정의되어 있지 않으면 이 코드는 컴파일됩니다. 컴파일러는 아무 작업도 하지 않는 부모의 빈 super() 생성자를 가장 먼저 호출해도 안전하다는 것을 알기 때문입니다.

따라서 다음 코드:

extern class Base {
}

class Child extends Base {
  var field = "hello";
}

다음과 같은 예상된 ES6 출력을 생성합니다:

class Child extends Base {
  constructor() {
    super();
    this.field = "hello";
  }
}

출처: ECMAScript 6 class generation

더 알아보기