静的メソッドを呼び出すための標準的な方法は何ですか?私は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
を使用すると、動的ディスパッチが使用され、現在のインスタンスのクラスが参照されます。静的プロパティmightは継承された値を持ちますが、オーバーライドすることもできます。
これは、クラス名またはインスタンスself
のいずれかを介して静的プロパティを参照するように選択できるPythonの動作と一致します。
静的プロパティが上書きされないように(そして常に現在のクラスの1つを参照するように)することを期待している場合、 Javaのように を明示的に参照してください。
私はこのスレッドでつまずいて似たような場合に対する答えを探しました。基本的にすべての答えが見つかりましたが、それらから本質を引き出すのはまだ難しいです。
おそらく他のクラスから派生したクラスFooが、おそらく他のクラスから派生しているとします。
それからアクセス
this.method()
this.property
Foo.method()
Foo.property
this.constructor.method()
this.constructor.property
this.method()
this.property
Foo.method()
Foo.property
Foo.prototype.method.call( this )
Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);
this
を使用しても、矢印関数を使用したり、カスタム値に明示的にバインドされたメソッド/ゲッターを呼び出したりする場合は、このようには機能しません。
this
は現在のインスタンスを参照しています。super
は基本的に同じインスタンスを参照していますが、現在のクラスのコンテキストで記述されたアドレス指定メソッドおよびゲッターは(Fooのプロトタイプのプロトタイプを使用して)拡張されています。this.constructor
ごとに利用可能です。this
は、現在のクラスの定義を直接参照するために利用できます。super
はいくつかのインスタンスも参照していませんが、現在のクラスが拡張しているクラスのコンテキストで記述された静的メソッドおよびゲッターを参照しています。このコードを試してください:
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!
をコンソールに記録しますtest4
はまだスーパークラスに属していると考えていることがわかります。この例では大したことには思えないかもしれませんが、オーバーライドされたメンバー関数または新しいメンバー変数を参照しようとしている場合は、困ったことに気付くでしょう。