JavaScript hat kein genaues Analogon für die Erweiterungsmethoden von C #. JavaScript und C # sind ganz unterschiedliche Sprachen.
Das nächste ähnliche Element ist das Ändern des Prototypobjekts aller Zeichenfolgenobjekte : String.prototype
. Im Allgemeinen wird empfohlen, die Prototypen integrierter Objekte im Bibliothekscode nicht zu ändern, um sie mit anderem Code zu kombinieren, den Sie nicht steuern. (Dies in einer Anwendung zu tun, in der Sie steuern, welcher andere Code in der Anwendung enthalten ist, ist in Ordnung.)
Wenn Sie tun , den Prototyp eine integrierten in ändern, ist es am besten (bei weitem) , dass eine machen , nicht-zählbare Eigenschaft mithilfe Object.defineProperty
(ES5 +, so dass im Grunde jeder modernen JavaScript - Umgebung und nicht IE8¹ oder früher). Um der Aufzählbarkeit, Beschreibbarkeit und Konfigurierbarkeit anderer Zeichenfolgenmethoden zu entsprechen, sieht es folgendermaßen aus:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
(Die Standardeinstellung für enumerable
ist false
.)
Wenn Sie veraltete Umgebungen unterstützen müssen, String.prototype
können Sie insbesondere möglicherweise eine aufzählbare Eigenschaft erstellen:
String.prototype.SayHi = function SayHi() {
return "Hi " + this + "!";
};
Das ist keine gute Idee, aber Sie könnten damit durchkommen. Mach das niemals mit Array.prototype
oder Object.prototype
; Das Erstellen von unzähligen Eigenschaften auf diesen ist eine schlechte Sache.
Einzelheiten:
JavaScript ist eine prototypische Sprache. Das bedeutet, dass jedes Objekt von einem Prototypobjekt unterstützt wird . In JavaScript wird dieser Prototyp auf vier Arten zugewiesen:
- Durch die Konstruktorfunktion für das Objekt (z. B.
new Foo
erstellt ein Objekt mit Foo.prototype
als Prototyp)
- Durch die
Object.create
in ES5 (2009) hinzugefügte Funktion
- Durch die
__proto__
Accessor-Eigenschaft (ES2015 +, nur in Webbrowsern, in einigen Umgebungen vorhanden, bevor sie standardisiert wurde) oder Object.setPrototypeOf
(ES2015 +)
- Von der JavaScript-Engine beim Erstellen eines Objekts für ein Grundelement, weil Sie eine Methode dafür aufrufen (dies wird manchmal als "Promotion" bezeichnet).
Da es sich in Ihrem Beispiel firstName
um ein Zeichenfolgenprimitiv handelt, wird es bei String
jedem Aufruf einer Methode zu einer Instanz heraufgestuft, und String
der Prototyp dieser Instanz ist String.prototype
. Wenn Sie also eine Eigenschaft hinzufügen, String.prototype
die auf Ihre SayHi
Funktion verweist , ist diese Funktion für alle String
Instanzen verfügbar (und effektiv für Zeichenfolgenprimitive, da diese heraufgestuft werden).
Beispiel:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
console.log("Charlie".SayHi());
Es gibt einige wesentliche Unterschiede zwischen dieser und der C # -Erweiterungsmethode:
(Wie DougR in einem Kommentar hervorhob ) Die Erweiterungsmethoden von C # können für null
Referenzen aufgerufen werden . Wenn Sie eine string
Erweiterungsmethode haben, lautet dieser Code:
string s = null;
s.YourExtensionMethod();
funktioniert. Das stimmt nicht mit JavaScript. null
ist ein eigener Typ, und jede Eigenschaftsreferenz auf null
löst einen Fehler aus. (Und selbst wenn dies nicht der Fall wäre, gibt es keinen Prototyp, der für den Null-Typ erweitert werden könnte.)
(Wie ChrisW in einem Kommentar betonte ) Die Erweiterungsmethoden von C # sind nicht global. Sie sind nur zugänglich, wenn der Namespace, in dem sie definiert sind, vom Code mithilfe der Erweiterungsmethode verwendet wird. (Sie sind wirklich syntaktischer Zucker für statische Aufrufe, weshalb sie funktionieren null
.) Das trifft in JavaScript nicht zu: Wenn Sie den Prototyp eines integrierten Systems ändern, wird diese Änderung von allen Codes im gesamten Bereich gesehen , in dem Sie sich befinden Tun Sie dies in (ein Bereich ist die globale Umgebung und die zugehörigen intrinsischen Objekte usw.). Wenn Sie dies auf einer Webseite tun, wird der gesamte Code, den Sie auf dieser Seite laden, geändert. Wenn Sie dies in einem Node.js-Modul tun, alleCode, der im selben Bereich wie dieses Modul geladen wurde, sieht die Änderung. In beiden Fällen tun Sie dies deshalb nicht im Bibliothekscode. (Web-Worker und Node.js Worker-Threads werden in ihrem eigenen Bereich geladen, sodass sie eine andere globale Umgebung und andere Eigenschaften als der Haupt-Thread haben. Dieser Bereich wird jedoch weiterhin mit allen von ihnen geladenen Modulen geteilt .)
¹ IE8 hat zwar Object.defineProperty
, funktioniert aber nur mit DOM-Objekten, nicht mit JavaScript-Objekten. String.prototype
ist ein JavaScript-Objekt.
String s = null;
Teils war zu verwendens.YourExtensionMethod()
! Schätzen Sie den Fang. :-)class MyArray extends Array { singleOrDefault() { ... }}
) erstellen. Dies bedeutet jedoch, dass Sie diesMyArray.from(originalArray)
vor der Verwendung tun müssen , wennoriginalArray
es sich um ein langweiliges altes Array handelt. Es gibt auch LINQ-ähnliche Bibliotheken für JavaScript ( hier eine Zusammenfassung ), bei denen ebenfalls ein Linq-Objekt aus dem Array erstellt wird, bevor Dinge ausgeführt werden (nun, LINQ zu JavaScript hat es getan, ich habe keine anderen verwendet [und dieses nicht verwendet) in Jahren]). (Übrigens, aktualisierte die Antwort, danke.)Verwenden der globalen Erweiterung
declare global { interface DOMRect { contains(x:number,y:number): boolean; } } /* Adds contain method to class DOMRect */ DOMRect.prototype.contains = function (x:number, y:number) { if (x >= this.left && x <= this.right && y >= this.top && y <= this.bottom) { return true } return false };
quelle