Qual è il modo standard per chiamare i metodi statici? Posso pensare di usare il constructor
o usare il nome della class stessa, non mi piace quest’ultimo dato che non sembra necessario. Il primo è il modo raccomandato, o c’è qualcos’altro?
Ecco un esempio (forzato):
class SomeObject { constructor(n){ this.n = n; } static print(n){ console.log(n); } printN(){ this.constructor.print(this.n); } }
Entrambi i modi sono fattibili, ma fanno cose diverse quando si tratta di ereditare con un metodo statico sovrascritto. Scegli quello il cui comportamento ti aspetti:
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
Il riferimento alla proprietà statica tramite la class sarà in effetti statico e fornirà costantemente lo stesso valore. L’uso di this.constructor
utilizzerà invece il dispatch dinamico e farà riferimento alla class dell’istanza corrente, in cui la proprietà statica potrebbe avere il valore ereditato ma potrebbe anche essere ignorata.
Corrisponde al comportamento di Python, in cui è ansible scegliere di fare riferimento alle proprietà statiche tramite il nome della class o l’ self
un’istanza.
Se si prevede che le proprietà statiche non debbano essere sovrascritte (e fare sempre riferimento a quella della class corrente), come in Java , utilizzare il riferimento esplicito.
Mi sono imbattuto in questo thread alla ricerca di una risposta a un caso simile. Fondamentalmente tutte le risposte sono state trovate, ma è ancora difficile estrarre l’essenziale da esse.
Assumiamo una class Foo probabilmente derivata da qualche altra class (o classi) con probabilmente più classi derivate da essa.
Quindi accedendo
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);
Tieni presente che l’utilizzo di
this
non funziona in questo modo quando si utilizzano le funzioni freccia o si invocano metodi / getters associati esplicitamente al valore personalizzato.
this
si riferisce all’istanza corrente. super
si riferisce fondamentalmente alla stessa istanza, ma in qualche modo si stanno estendendo metodi e getter scritti nel contesto di una class corrente (usando il prototipo del prototipo di Foo). this.constructor
. this
è disponibile per fare riferimento direttamente alla definizione della class corrente. super
non si riferisce ad alcuna istanza, ma a metodi statici e getter scritti nel contesto di una class corrente si sta estendendo. Prova questo codice:
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 );
Se stai pensando di fare qualsiasi tipo di ereditarietà, allora ti consiglio this.constructor
. Questo semplice esempio dovrebbe illustrare il motivo:
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()
registrerà ConstructorSuper Hello ConstructorSuper!
alla console test2.callPrint()
registrerà ConstructorSub Hello ConstructorSub!
alla console La class denominata non gestirà l’ereditarietà in modo appropriato a meno che non si ridefinisca esplicitamente ogni funzione che fa riferimento alla class denominata. Ecco un esempio:
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()
registrerà NamedSuper Hello NamedSuper!
alla console test4.callPrint()
registrerà NamedSuper Hello NamedSub!
alla console Vedi tutto quanto sopra in esecuzione in Babel REPL .
Potete vedere da ciò che test4
pensa ancora che sia nella super class; in questo esempio potrebbe non sembrare un grosso problema, ma se stai provando a fare riferimento a funzioni membro che sono state sostituite oa nuove variabili membro, ti troverai nei guai.