[javascript] 일반 ES6 클래스 메소드에서 정적 메소드 호출

정적 메소드를 호출하는 표준 방법은 무엇입니까? 나는 constructor클래스 자체의 이름 을 사용 하거나 사용할 것을 생각할 수 있습니다 . 필요하지 않다고 생각하기 때문에 후자를 좋아하지 않습니다. 전자가 권장되는 방법입니까, 아니면 다른 것이 있습니까?

다음은 (고려 된) 예입니다.

class SomeObject {
  constructor(n){
    this.n = n;
  }

  static print(n){
    console.log(n);
  }

  printN(){
    this.constructor.print(this.n);
  }
}



답변

두 방법 모두 실행 가능하지만 재정의 된 정적 메서드를 사용하여 상속 할 때 다른 작업을 수행합니다. 행동이 예상되는 것을 선택하십시오 :

class Super {
  static whoami() {
    return "Super";
  }
  lognameA() {
    console.log(Super.whoami());
  }
  lognameB() {
    console.log(this.constructor.whoami());
  }
}
class Sub extends Super {
  static whoami() {
    return "Sub";
  }
}
new Sub().lognameA(); // Super
new Sub().lognameB(); // Sub

클래스를 통해 정적 속성을 참조하면 실제로 정적이며 지속적으로 동일한 값을 제공합니다. 사용하여 this.constructor동적 파견을 사용하고 정적 속성은 현재 인스턴스의 클래스를 참조 할 대신 할 수 상속 된 값을 가질뿐만 아니라, 오버라이드 (override) 할 수 있습니다.

이것은 클래스 이름이나 instance를 통해 정적 속성을 참조하도록 선택할 수있는 Python의 동작과 일치합니다 self.

Java 에서처럼 정적 특성이 대체되지 않고 항상 현재 클래스 중 하나를 참조 할 것으로 예상되는 경우 명시 적 참조를 사용하십시오.


답변

비슷한 사례에 대한 답을 찾기 위해이 스레드를 우연히 발견했습니다. 기본적으로 모든 답변이 있지만 여전히 필수 답변을 추출하기는 어렵습니다.

접근의 종류

아마도 다른 클래스에서 파생 된 Foo 클래스가 더 많은 클래스에서 파생되었다고 가정하십시오.

그런 다음

  • Foo의 정적 메소드 / getter에서
    • 아마도 재정의 된 정적 메소드 / getter :
      • this.method()
      • this.property
    • 아마도 재정의 된 인스턴스 메소드 / getter :
      • 의도적으로 불가능
    • 자신의 오버라이드 (override)되지 않는 정적의 방법 / 게터 :
      • Foo.method()
      • Foo.property
    • 재정의되지 않은 자체 인스턴스 메소드 / 게터 :
      • 의도적으로 불가능
  • Foo의 인스턴스 메소드 / getter에서
    • 아마도 재정의 된 정적 메소드 / getter :
      • this.constructor.method()
      • this.constructor.property
    • 아마도 재정의 된 인스턴스 메소드 / getter :
      • this.method()
      • this.property
    • 자신의 오버라이드 (override)되지 않는 정적의 방법 / 게터 :
      • Foo.method()
      • Foo.property
    • 재정의되지 않은 자체 인스턴스 메소드 / 게터 :
      • 해결 방법을 사용하지 않으면 의도적으로 불가능합니다 .
        • Foo.prototype.method.call( this )
        • Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);

사용하는 것을 명심 this화살표 기능을 사용하거나 메소드를 호출 할 때이 방법을 작동하지 않습니다 / 게터가 명시 적으로 사용자 정의 값에 바인딩.

배경

  • 인스턴스의 메소드 또는 getter와 관련하여
    • this 현재 인스턴스를 참조하고 있습니다.
    • super 기본적으로 동일한 인스턴스를 참조하지만 현재 일부 클래스와 관련하여 작성된 메서드 및 getter를 다소 확장하고 있습니다 (Foo 프로토 타입의 프로토 타입을 사용하여).
    • 인스턴스 생성에 사용 된 인스턴스 클래스의 정의는에 따라 제공됩니다 this.constructor.
  • 정적 메소드 또는 getter와 관련하여 의도적으로 “현재 인스턴스”가없는 경우
    • this 현재 클래스의 정의를 직접 참조 할 수 있습니다.
    • super 일부 인스턴스를 참조하는 것이 아니라 현재 일부 클래스의 컨텍스트에서 작성된 정적 메소드 및 getter가 확장되고 있습니다.

결론

이 코드를 사용해보십시오 :

class A {
  constructor( input ) {
    this.loose = this.constructor.getResult( input );
    this.tight = A.getResult( input );
    console.log( this.scaledProperty, Object.getOwnPropertyDescriptor( A.prototype, "scaledProperty" ).get.call( this ) );
  }

  get scaledProperty() {
    return parseInt( this.loose ) * 100;
  }

  static getResult( input ) {
    return input * this.scale;
  }

  static get scale() {
    return 2;
  }
}

class B extends A {
  constructor( input ) {
    super( input );
    this.tight = B.getResult( input ) + " (of B)";
  }

  get scaledProperty() {
    return parseInt( this.loose ) * 10000;
  }

  static get scale() {
    return 4;
  }
}

class C extends B {
  constructor( input ) {
    super( input );
  }

  static get scale() {
    return 5;
  }
}

class D extends C {
  constructor( input ) {
    super( input );
  }

  static getResult( input ) {
    return super.getResult( input ) + " (overridden)";
  }

  static get scale() {
    return 10;
  }
}


let instanceA = new A( 4 );
console.log( "A.loose", instanceA.loose );
console.log( "A.tight", instanceA.tight );

let instanceB = new B( 4 );
console.log( "B.loose", instanceB.loose );
console.log( "B.tight", instanceB.tight );

let instanceC = new C( 4 );
console.log( "C.loose", instanceC.loose );
console.log( "C.tight", instanceC.tight );

let instanceD = new D( 4 );
console.log( "D.loose", instanceD.loose );
console.log( "D.tight", instanceD.tight );


답변

어떤 종류의 상속을 계획하고 있다면 권장 this.constructor합니다. 이 간단한 예는 이유를 설명해야합니다.

class ConstructorSuper {
  constructor(n){
    this.n = n;
  }

  static print(n){
    console.log(this.name, n);
  }

  callPrint(){
    this.constructor.print(this.n);
  }
}

class ConstructorSub extends ConstructorSuper {
  constructor(n){
    this.n = n;
  }
}

let test1 = new ConstructorSuper("Hello ConstructorSuper!");
console.log(test1.callPrint());

let test2 = new ConstructorSub("Hello ConstructorSub!");
console.log(test2.callPrint());
  • test1.callPrint()ConstructorSuper Hello ConstructorSuper!콘솔에 기록 합니다
  • test2.callPrint()ConstructorSub Hello ConstructorSub!콘솔에 기록 합니다

명명 된 클래스는 명명 된 클래스를 참조하는 모든 함수를 명시 적으로 재정의하지 않는 한 상속을 잘 처리하지 않습니다. 예를 들면 다음과 같습니다.

class NamedSuper {
  constructor(n){
    this.n = n;
  }

  static print(n){
    console.log(NamedSuper.name, n);
  }

  callPrint(){
    NamedSuper.print(this.n);
  }
}

class NamedSub extends NamedSuper {
  constructor(n){
    this.n = n;
  }
}

let test3 = new NamedSuper("Hello NamedSuper!");
console.log(test3.callPrint());

let test4 = new NamedSub("Hello NamedSub!");
console.log(test4.callPrint());
  • test3.callPrint()NamedSuper Hello NamedSuper!콘솔에 기록 합니다
  • test4.callPrint()NamedSuper Hello NamedSub!콘솔에 기록 합니다

Babel REPL에서 실행중인 위의 모든 내용을 참조하십시오 .

test4여전히 슈퍼 클래스에 있다고 생각하는 것을 볼 수 있습니다 . 이 예에서는 별다른 문제가 아닌 것 같지만 재정의 된 멤버 함수 나 새 멤버 변수를 참조하려고하면 문제가 생길 수 있습니다.


답변