JavaScript n'a pas d'équivalent exact des méthodes d'extension de C#. JavaScript et C# sont des langages très différents.
La chose la plus proche est de modifier l'objet prototype de tous les objets chaîne : String.prototype
. En général, la meilleure pratique est pas pour modifier les prototypes d'objets intégrés dans du code de bibliothèque destiné à être combiné avec d'autres codes que vous ne contrôlez pas. (Le faire dans une application où vous contrôlez quel autre code est inclus dans l'application est acceptable).
Si vous faire modifier le prototype d'un intégré, il est préférable (de loin) de faire de ce dernier un non dénombrable en utilisant Object.defineProperty
(ES5+, donc en gros tout environnement JavaScript moderne, et non IE8¹ ou antérieur). Pour correspondre à la possibilité d'énumération, d'écriture et de configuration des autres méthodes de chaîne, cela ressemblerait à ceci :
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
(La valeur par défaut pour enumerable
est false
.)
Si vous aviez besoin de prendre en charge des environnements obsolètes, alors pour String.prototype
En particulier, vous pourriez probablement vous en sortir en créant une propriété énumérable :
// Don't do this if you can use `Object.defineProperty`
String.prototype.SayHi = function SayHi() {
return "Hi " + this + "!";
};
Ce n'est pas une bonne idée, mais vous pourriez vous en sortir. Jamais faire cela avec Array.prototype
ou Object.prototype
; créer des propriétés énumérables sur ceux-ci est une mauvaise chose™.
Détails :
JavaScript est un langage prototypique. Cela veut dire que chaque objet est soutenu par un objet objet prototype . En JavaScript, ce prototype est attribué de l'une des quatre manières suivantes :
- Par le fonction constructeur pour l'objet (par exemple,
new Foo
crée un objet avec Foo.prototype
comme son prototype)
- Par le
Object.create
fonction ajoutée dans ES5 (2009)
- Par le
__proto__
(ES2015+, uniquement sur les navigateurs web, existait dans certains environnements avant d'être normalisé) ou Object.setPrototypeOf
(ES2015+)
- Par le moteur JavaScript lors de la création d'un objet pour une primitive parce que vous appelez une méthode sur celle-ci (ceci est parfois appelé "promotion").
Donc, dans votre exemple, puisque firstName
est une primitive de type chaîne de caractères, elle est promue au rang de String
à chaque fois que vous appelez une méthode sur lui, et cela String
Le prototype de l'instance est String.prototype
. Ainsi, l'ajout d'une propriété à String.prototype
qui fait référence à votre SayHi
rend cette fonction disponible sur tous les String
(et effectivement sur les primitives de type chaîne, car elles sont promues).
Exemple :
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
console.log("Charlie".SayHi());
Il existe quelques différences essentielles entre cette méthode et les méthodes d'extension C# :
-
(Comme DougR souligné dans un commentaire) Les méthodes d'extension de C# peut être appelé sur null
références . Si vous avez un string
méthode d'extension, ce code :
string s = null;
s.YourExtensionMethod();
travaux. Ce n'est pas le cas avec JavaScript ; null
est son propre type, et toute référence de propriété sur null
lance une erreur. (Et même si ce n'était pas le cas, il n'y a pas de prototype à étendre pour le type Null).
-
(Comme ChrisW souligné dans un commentaire) Les méthodes d'extension de C# ne sont pas globales. Elles ne sont accessibles que si l'espace de nom dans lequel elles sont définies est utilisé par le code qui utilise la méthode d'extension. (Il s'agit en fait d'un sucre syntaxique pour les appels statiques, ce qui explique pourquoi elles fonctionnent sur le modèle null
.) Ce n'est pas vrai en JavaScript : Si vous modifiez le prototype d'un élément intégré, cette modification est vue par tous dans l'ensemble du domaine dans lequel vous faites cela (un domaine est l'environnement global et ses objets intrinsèques associés, etc.) Donc si vous faites ça dans une page web, tous le code que vous chargez sur cette page voit le changement. Si vous faites ça dans un module Node.js, tous Le code chargé dans le même domaine que ce module verra le changement. Dans les deux cas, c'est pourquoi vous ne faites pas cela dans le code de la bibliothèque. (Les travailleurs Web et les threads de travail Node.js sont chargés dans leur propre domaine, ils ont donc un environnement global différent et des éléments intrinsèques différents de ceux du thread principal. Mais ce domaine est toujours partagé avec tous les modules. ils charge.)
¹ IE8 a Object.defineProperty
mais il ne fonctionne que sur les objets DOM, pas sur les objets JavaScript. String.prototype
est un objet JavaScript.