Ich weiß, dass das funktionieren wird:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
Aber wenn ich anrufen will
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
Ich finde einige Methoden, um Foo.talk
Arbeit zu machen ,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
Gibt es andere Möglichkeiten, dies zu tun? Ich weiß nicht, ob es richtig ist. Verwenden Sie Klassenmethoden oder statische Methoden in Ihrem JavaScript-Code?
javascript
oop
lostyzd
quelle
quelle
Foo.talk = function ...
Foo.walk = function() {}
wirkt sich nicht auf seine Instanzen aus, da es sich nicht in der Prototypenkette befindet. Gibt es eine browserübergreifende Methode, um die Funktion einer Funktion[[prototype]]
hervorzuhebenprototype
?this
Zeiger.Antworten:
Denken Sie zunächst daran, dass JavaScript in erster Linie eine prototypische Sprache und keine klassenbasierte Sprache ist 1 .
Foo
ist keine Klasse, es ist eine Funktion, die ein Objekt ist. Sie können ein Objekt aus dieser Funktion mithilfe desnew
Schlüsselworts instanziieren , mit dem Sie etwas Ähnliches wie eine Klasse in einer Standard-OOP-Sprache erstellen können.Ich würde vorschlagen, die
__proto__
meiste Zeit zu ignorieren, da es keine browserübergreifende Unterstützung bietet, und sich stattdessen darauf zu konzentrieren, zu lernen, wie esprototype
funktioniert.Wenn Sie eine Instanz eines Objekts aus einer Funktion 2 erstellt haben und auf eines ihrer Elemente (Methoden, Attribute, Eigenschaften, Konstanten usw.) zugreifen, fließt der Zugriff durch die Prototyphierarchie, bis entweder (a) das gefunden wird Mitglied, oder (b) findet keinen anderen Prototyp.
Die Hierarchie beginnt mit dem aufgerufenen Objekt und durchsucht dann das Prototypobjekt. Wenn das Prototypobjekt einen Prototyp hat, wird es wiederholt, wenn kein Prototyp vorhanden
undefined
ist, zurückgegeben.Beispielsweise:
Es sieht für mich so aus, als hätten Sie diese "grundlegenden" Teile zumindest schon ein wenig verstanden, aber ich muss sie explizit machen, nur um sicherzugehen.
In JavaScript ist alles ein Objekt 3 .
Alles ist ein Objekt.
function Foo(){}
definiert nicht nur eine neue Funktion, sondern ein neues Funktionsobjekt, auf das mit zugegriffen werden kannFoo
.Aus diesem Grund können Sie mit auf
Foo
den Prototyp zugreifenFoo.prototype
.Was Sie auch tun wird mehr Funktionen auf
Foo
:Auf diese neue Funktion kann zugegriffen werden mit:
Ich hoffe, dass Sie jetzt eine Ähnlichkeit zwischen Funktionen eines Funktionsobjekts und einer statischen Methode feststellen.
Stellen Sie sich vor
f = new Foo();
, Sie erstellen eine Klasseninstanz,Foo.prototype.bar = function(){...}
definieren eine gemeinsame Methode für die Klasse undFoo.baz = function(){...}
definieren eine öffentliche statische Methode für die Klasse.ECMAScript 2015 führte eine Vielzahl von syntaktischen Zuckern für diese Art von Deklarationen ein, um deren Implementierung zu vereinfachen und gleichzeitig die Lesbarkeit zu verbessern. Das vorherige Beispiel kann daher wie folgt geschrieben werden:
was erlaubt
bar
, als bezeichnet zu werden:und
baz
genannt werden als:1:
class
war ein "Future Reserved Word" in der ECMAScript 5-Spezifikation , aber ES6 bietet die Möglichkeit, Klassen mithilfe desclass
Schlüsselworts zu definieren .2: Im Wesentlichen eine Klasseninstanz, die von einem Konstruktor erstellt wurde, aber es gibt viele nuancierte Unterschiede, die ich Sie nicht irreführen möchte
3: Primitive Werte , zu denen Boolesche Werte , Zahlen und Zeichenfolgen gehören
undefined
,null
sind technisch gesehen keine Objekte, da es sich um Sprachimplementierungen auf niedriger Ebene handelt. Boolesche Werte, Zahlen und Zeichenfolgen interagieren immer noch mit der Prototypenkette, als wären sie Objekte. Für die Zwecke dieser Antwort ist es daher einfacher, sie als "Objekte" zu betrachten, obwohl sie nicht ganz sind.quelle
Foo.talk()
. Sie können dies im Konstruktor zuweisen, wenn Sie möchten:this.talk = Foo.talk
- oder, wie Sie bemerken, durch ZuweisenFoo.prototype.talk = Foo.talk
. Ich bin mir jedoch nicht sicher, ob dies eine gute Idee ist. Grundsätzlich sollten Instanzmethoden spezifisch für die Instanz sein.Foo.talk()
ruft gerade eine Namespace-Funktion auf. Sie würden es in Situationen verwenden, in denen statische Methoden in OOP-Sprachen wie Java / C # aufgerufen werden. Ein gutes Beispiel für einen Anwendungsfall wäre eine Funktion wieArray.isArray()
.Foo.talk = function ()...
wird für Unterklassen mit eigenem Klassennamen nicht verfügbar sein. Dies kann durch "Erweitern" von Unterklassen umgangen werden, aber ich suche auch immer noch nach einem eleganteren Weg.Sie können es wie folgt erreichen:
Sie können jetzt die "Talk" -Funktion wie folgt aufrufen:
Sie können dies tun, da Funktionen in JavaScript ebenfalls Objekte sind.
quelle
Rufen Sie eine statische Methode aus einer Instanz auf:
Einfaches Javascript-Klassenprojekt: https://github.com/reduardo7/sjsClass
quelle
Clazz.staticMethod
sondern er zeigt Ihnen auch, wie Sie innerhalb eines instanziierten Objekts eine Verknüpfung zu diesen statischen Methoden herstellen. Dies ist besonders nützlich in Umgebungen wie Node.js, in denen Sie mit require möglicherweise keinen direkten Zugriff auf den ursprünglichen Konstruktor haben. Das einzige, was ich hinzufügen möchte, istthis.constructor.staticMethod.apply(this, arguments);
constructor: (a) -> @constructor.add @
(Hier ist ein gutes Beispiel, um zu demonstrieren, wie Javascript mit statischen / Instanzvariablen und -methoden funktioniert.
quelle
this
.this
Schlüsselwort gebenZusätzlich ist es jetzt möglich, mit
class
und zu tunstatic
wird geben
quelle
Ich benutze Namespaces:
Und um es zu benutzen:
Oder
quelle
ES6 unterstützt jetzt
class
&static
Schlüsselwörter wie ein Zauber:quelle
Wenn Sie statische Methoden in ES5 schreiben müssen, habe ich dafür ein großartiges Tutorial gefunden:
siehe @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
quelle
Nur zusätzliche Notizen. Verwenden der Klasse ES6: Wenn wir statische Methoden erstellen, setzt die Javacsript-Engine das Deskriptorattribut ein kleines bisschen anders als die "statische" Methode der alten Schule
Es setzt das interne Attribut (Deskriptoreigenschaft) für brand () auf
verglichen mit
Damit wird das interne Attribut für brand () auf gesetzt
Sehen Sie, dass enumerable für die statische Methode in ES6 auf false gesetzt ist .
Dies bedeutet, dass Sie die For-In-Schleife nicht zum Überprüfen des Objekts verwenden können
Die statische Methode in ES6 wird wie die private Eigenschaft einer anderen Klasse (Name, Länge, Konstruktor) behandelt, mit der Ausnahme, dass die statische Methode weiterhin beschreibbar ist und der beschreibbare Deskriptor auf true gesetzt ist
{ writable: true }
. es bedeutet auch, dass wir es überschreiben könnenquelle
Wenn Sie zu nennen versuchen
Foo.talk
, versucht der JS eine Funktion zur Suchetalk
durch__proto__
und, natürlich, es kann nicht gefunden werden.Foo.__proto__
istFunction.prototype
.quelle
Statische Methodenaufrufe werden direkt in der Klasse ausgeführt und können in Instanzen der Klasse nicht aufgerufen werden. Statische Methoden werden häufig verwendet, um Dienstprogrammfunktionen zu erstellen
Ziemlich klare Beschreibung
Direkt von mozilla.org genommen
Foo muss an Ihre Klasse gebunden sein Wenn Sie dann eine neue Instanz erstellen, können Sie myNewInstance.foo () aufrufen. Wenn Sie Ihre Klasse importieren, können Sie eine statische Methode aufrufen
quelle
Als ich in eine solche Situation geriet, habe ich so etwas getan:
so kann ich jetzt die info methode als aufrufen
Logger.info("my Msg", "Tag");
quelle
In Ihrem Fall, wenn Sie möchten
Foo.talk()
:Aber es ist eine ineffiziente Art zu implementieren, die Verwendung
prototype
ist besser.Ein anderer Weg, Mein Weg ist als statische Klasse definiert:
Die oben genannte statische Klasse muss nicht verwendet werden,
prototype
da sie nur einmal als statische Verwendung erstellt wird.quelle
Javascript hat keine tatsächlichen Klassen, sondern verwendet ein System der prototypischen Vererbung, bei dem Objekte über ihre Prototypenkette von anderen Objekten "erben". Dies lässt sich am besten über den Code selbst erklären:
quelle