Metodo Class vs. static in JavaScript

So che funzionerà:

function Foo() {}; Foo.prototype.talk = function () { alert('hello~\n'); }; var a = new Foo; a.talk(); // 'hello~\n' 

Ma se voglio chiamare

 Foo.talk() // this will not work Foo.prototype.talk() // this works correctly 

Trovo alcuni metodi per far funzionare Foo.talk ,

  1. Foo.__proto__ = Foo.prototype
  2. Foo.talk = Foo.prototype.talk

C’è qualche altro modo per farlo? Non so se sia giusto farlo. Usi metodi di class o metodi statici nel tuo codice JavaScript?

Innanzitutto, ricorda che JavaScript è principalmente un linguaggio prototipale , piuttosto che un linguaggio basato sulla class 1 . Foo non è una class, è una funzione, che è un object. Puoi istanziare un object da quella funzione usando la new parola chiave che ti permetterà di creare qualcosa di simile a una class in un linguaggio OOP standard.

Suggerirei di ignorare __proto__ più delle volte perché ha uno scarso supporto per i browser incrociati e preferisco concentrarsi sull’apprendimento del funzionamento del prototype .

Se si ha un’istanza di un object creato da una funzione 2 e si accede a uno dei suoi membri (metodi, attributi, proprietà, costanti ecc.), L’accesso scorrerà lungo la gerarchia del prototipo fino a quando (a) non trova membro, o (b) non trova un altro prototipo.

La gerarchia inizia sull’object che è stato chiamato, quindi cerca il suo object prototipo. Se l’object prototipo ha un prototipo, si ripete, se non esiste alcun prototipo, viene restituito undefined .

Per esempio:

 foo = {bar: 'baz'}; alert(foo.bar); //alerts "baz" foo = {}; alert(foo.bar); //alerts undefined function Foo(){} Foo.prototype = {bar: 'baz'}; f = new Foo(); alert(f.bar); //alerts "baz" because the object f doesn't have an attribute "bar" //so it checks the prototype f.bar = 'buzz'; alert( f.bar ); //alerts "buzz" because f has an attribute "bar" set 

Mi sembra che tu abbia almeno in qualche modo capito queste parti “di base”, ma ho bisogno di renderle esplicite solo per essere sicuro.

In JavaScript, tutto è un object 3 .

tutto è un object.

function Foo(){} non definisce semplicemente una nuova funzione, ma definisce un nuovo object funzione a cui è ansible accedere usando Foo .

Questo è il motivo per cui è ansible accedere al prototipo di Foo con Foo.prototype .

Quello che puoi fare è anche impostare più funzioni su Foo :

 Foo.talk = function () { alert('hello world!'); }; 

È ansible accedere a questa nuova funzione utilizzando:

 Foo.talk(); 

Spero che ora noti una somiglianza tra le funzioni su un object funzione e un metodo statico.

Pensa a f = new Foo(); come creare un’istanza di class, Foo.prototype.bar = function(){...} come definizione di un metodo condiviso per la class, e Foo.baz = function(){...} come definizione di un metodo statico pubblico per class.


ECMAScript 2015 ha introdotto una varietà di zucchero sintattico per questo tipo di dichiarazioni per renderle più semplici da implementare e allo stesso tempo essere più facili da leggere. L’esempio precedente può quindi essere scritto come:

 class Foo { bar() {...} static baz() {...} } 

che consente di chiamare la bar come:

 const f = new Foo() f.bar() 

e baz per essere chiamato come:

 Foo.baz() 

1: class era un “Future Reserved Word” nella specifica ECMAScript 5 , ma ES6 introduce la possibilità di definire le classi usando la parola chiave class .

2: essenzialmente un’istanza di class creata da un costruttore, ma ci sono molte differenze sfumate che non voglio trarre in inganno

3: valori primitivi -che includono undefined , null , booleani, numeri e stringhe- non sono tecnicamente oggetti perché sono implementazioni linguistiche di basso livello. Booleans, numeri e stringhe interagiscono ancora con la catena del prototipo come se fossero oggetti, quindi per gli scopi di questa risposta è più semplice considerarli “oggetti” anche se non sono abbastanza.

Puoi ottenerlo come di seguito:

 function Foo() {}; Foo.talk = function() { alert('I am talking.'); }; 

Ora puoi invocare la funzione “talk” come di seguito:

 Foo.talk(); 

Puoi farlo perché in JavaScript le funzioni sono anche oggetti. “zzzzBov” ha risposto, ma è una lettura lunga.

Chiama un metodo statico da un’istanza:

 function Clazz() {}; Clazz.staticMethod = function() { alert('STATIC!!!'); }; Clazz.prototype.func = function() { this.constructor.staticMethod(); } var obj = new Clazz(); obj.func(); // <- Alert's "STATIC!!!" 

Semplice progetto di class Javascript: https://github.com/reduardo7/sjsClass

Ecco un buon esempio per dimostrare come JavaScript funzioni con variabili e metodi statici / di istanza.

 function Animal(name) { Animal.count = Animal.count+1||1;// static variables, use function name "Animal" this.name = name; //instance variable, using "this" } Animal.showCount = function () {//static method alert(Animal.count) } Animal.prototype.showName=function(){//instance method alert(this.name); } var mouse = new Animal("Mickey"); var elephant = new Animal("Haddoop"); Animal.showCount(); // static method, count=2 mouse.showName();//instance method, alert "Mickey" mouse.showCount();//Error!! mouse.showCount is not a function, which is different from Java 

In aggiunta, ora è ansible fare con class e static

 'use strict' class Foo { static talk() { console.log('talk') }; speak() { console.log('speak') }; }; 

darà

 var a = new Foo(); Foo.talk(); // 'talk' a.talk(); // err 'is not a function' a.speak(); // 'speak' Foo.speak(); // err 'is not a function' 

Io uso gli spazi dei nomi:

 var Foo = { element: document.getElementById("id-here"), Talk: function(message) { alert("talking..." + message); }, ChangeElement: function() { this.element.style.color = "red"; } }; 

E per usarlo:

 Foo.Talk("Testing"); 

O

 Foo.ChangeElement(); 

ES6 supporta ora parole chiave class e static come un fascino:

 class Foo { constructor() {} talk() { console.log("i am not static"); } static saying() { console.log(this.speech); } static get speech() { return "i am static method"; } } 

Se devi scrivere metodi statici in ES5 ho trovato un ottimo tutorial per questo:

 //Constructor var Person = function (name, age){ //private properties var priv = {}; //Public properties this.name = name; this.age = age; //Public methods this.sayHi = function(){ alert('hello'); } } // A static method; this method only // exists on the class and doesn't exist // on child objects Person.sayName = function() { alert("I am a Person object ;)"); }; 

vedere @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/

Quando provate a chiamare Foo.talk , il JS prova a cercare una funzione talk attraverso __proto__ e, ovviamente, non può essere trovata.

Foo.__proto__ è Function.prototype .

Quando ho affrontato una situazione del genere, ho fatto qualcosa del genere:

 Logger = { info: function (message, tag) { var fullMessage = ''; fullMessage = this._getFormatedMessage(message, tag); if (loggerEnabled) { console.log(fullMessage); } }, warning: function (message, tag) { var fullMessage = ''; fullMessage = this._getFormatedMessage(message, tag); if (loggerEnabled) { console.warn(fullMessage);`enter code here` } }, _getFormatedMessage: function () {} }; 

così ora posso chiamare il metodo info come Logger.info("my Msg", "Tag");

Nel tuo caso, se vuoi Foo.talk() :

 function Foo() {}; // But use Foo.talk would be inefficient Foo.talk = function () { alert('hello~\n'); }; Foo.talk(); // 'hello~\n' 

Ma è un modo inefficiente di implementare, usare il prototype è meglio.


Un altro modo, La mia strada è definita come class statica:

 var Foo = new function() { this.talk = function () { alert('hello~\n'); }; }; Foo.talk(); // 'hello~\n' 

Sopra la class statica non è necessario utilizzare il prototype perché verrà costruito una sola volta come utilizzo statico.

https://github.com/yidas/js-design-patterns/tree/master/class

Le chiamate al metodo statico vengono eseguite direttamente sulla class e non possono essere richiamate su istanze della class. I metodi statici sono spesso usati per creare funzioni di utilità

Descrizione abbastanza chiara

Preso direttamente da mozilla.org

Foo deve essere associato alla tua class Quindi quando crei una nuova istanza puoi chiamare myNewInstance.foo () Se imponi la tua class puoi chiamare un metodo statico

Solo note aggiuntive. Usando la class ES6, Quando creiamo metodi statici … il motore Javacsript imposta l’attributo descrittore un po ‘diverso dal metodo “statico” della vecchia scuola

 function Car() { } Car.brand = function() { console.log('Honda'); } console.log( Object.getOwnPropertyDescriptors(Car) ); 

imposta l’attributo interno (proprietà descrittore) per brand () su

 .. brand: [object Object] { configurable: true, enumerable: true, value: .. writable: true } .. 

rispetto a

 class Car2 { static brand() { console.log('Honda'); } } console.log( Object.getOwnPropertyDescriptors(Car2) ); 

che imposta l’attributo interno per brand () a

 .. brand: [object Object] { configurable: true, enumerable: false, value:.. writable: true } .. 

vedere che enumerable è impostato su false per il metodo statico in ES6.

significa che non puoi usare il ciclo for-in per controllare l’object

 for (let prop in Car) { console.log(prop); // brand } for (let prop in Car2) { console.log(prop); // nothing here } 

il metodo statico in ES6 viene trattato come proprietà privata di class di altri (nome, lunghezza, costruttore) eccetto che il metodo statico è ancora scrivibile, quindi il descrittore scrivibile è impostato su true { writable: true } . significa anche che possiamo ignorarlo

 Car2.brand = function() { console.log('Toyota'); }; console.log( Car2.brand() // is now changed to toyota );