JavaScript 没有与 C# 的扩展方法完全类似的东西。 JavaScript 和 C# 是完全不同的语言。
最接近的类似的事情是修改所有字符串对象的原型对象:String.prototype。一般来说,最佳做法是不修改库代码中旨在与您无法控制的其他代码组合的内置对象的原型。 (在您控制应用程序中包含的其他代码的应用程序中执行此操作是可以的。)
如果您确实修改了内置的原型,最好(到目前为止)使用Object.defineProperty(ES5+ ,所以基本上是任何现代 JavaScript 环境,而不是 IE8¹ 或更早版本)。为了匹配其他字符串方法的可枚举性、可写性和可配置性,它看起来像这样:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
(enumerable 的默认值为false。)
如果您需要支持过时的环境,那么对于 String.prototype,具体来说,您可能会通过创建一个可枚举的属性而侥幸:
// Don't do this if you can use `Object.defineProperty`
String.prototype.SayHi = function SayHi() {
return "Hi " + this + "!";
};
这不是一个好主意,但你可能会侥幸逃脱。 永远不要对 Array.prototype 或 Object.prototype 这样做;在这些上创建可枚举的属性是一件坏事™。
详情:
JavaScript 是一种原型语言。这意味着每个对象都有一个原型对象。在 JavaScript 中,该原型以以下四种方式之一分配:
- 通过对象的构造函数(例如,
new Foo 创建一个以Foo.prototype 为原型的对象)
- 由 ES5 (2009) 中添加的
Object.create 函数
- 通过
__proto__ 访问器属性(ES2015+,仅在 Web 浏览器上,在标准化之前存在于某些环境中)或 Object.setPrototypeOf (ES2015+)
- 在为基元创建对象时由 JavaScript 引擎调用,因为您在其上调用方法(这有时称为“提升”)
因此,在您的示例中,由于firstName 是一个字符串原语,因此只要您对其调用方法,它就会被提升为String 实例,并且String 实例的原型是String.prototype。因此,向 String.prototype 添加一个引用您的 SayHi 函数的属性可以使该函数在所有 String 实例上都可用(并且有效地在字符串原语上,因为它们被提升了)。
例子:
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
console.log("Charlie".SayHi());
此方法与 C# 扩展方法之间存在一些关键区别:
有效(除非YourExtensionMethod 在接收到null 作为实例参数时抛出)。 JavaScript 不是这样。 null 是它自己的类型,null 上的任何属性引用都会引发错误。 (即使没有,也没有可以为 Null 类型扩展的原型。)
-
(正如ChrisW 在评论中指出的那样) C# 的扩展方法不是全局的。仅当使用扩展方法的代码使用它们定义的命名空间时,它们才可访问。 (它们实际上是静态调用的语法糖,这就是它们在
null 上工作的原因。)在 JavaScript 中情况并非如此:如果您更改内置函数的原型,则 all 会看到该更改 在您执行此操作的整个领域中的代码(领域是全局环境及其关联的内在对象等)。因此,如果您在网页中执行此操作,您在该网页上加载的 所有 代码都会看到更改。如果您在 Node.js 模块中执行此操作,则在与该模块相同的领域中加载的 所有 代码将看到更改。在这两种情况下,这就是您不在库代码中执行此操作的原因。 (Web 工作线程和 Node.js 工作线程加载在它们自己的领域中,因此它们具有与主线程不同的全局环境和不同的内在函数。但是该领域仍然与它们加载的任何模块共享。 )
¹ IE8 确实有Object.defineProperty,但它只适用于 DOM 对象,而不适用于 JavaScript 对象。 String.prototype 是一个 JavaScript 对象。