gpt4 book ai didi

javascript - 如何在 JavaScript 中编写扩展方法?

转载 作者:IT王子 更新时间:2023-10-29 02:50:54 26 4
gpt4 key购买 nike

我需要在JS中编写一些扩展方法。我知道如何在 C# 中做到这一点。示例:

public static string SayHi(this Object name)
{
return "Hi " + name + "!";
}

然后通过以下方式调用:
string firstName = "Bob";
string hi = firstName.SayHi();

我将如何在 JavaScript 中做这样的事情?

最佳答案

JavaScript 没有与 C# 的扩展方法完全类似的东西。 JavaScript 和 C# 是完全不同的语言。

最接近类似的就是修改所有字符串对象的原型(prototype)对象:String.prototype .一般来说,最佳实践是 不是 修改旨在与您无法控制的其他代码组合的库代码中内置对象的原型(prototype)。 (在您控制应用程序中包含哪些其他代码的应用程序中执行此操作是可以的。)

如果您确实修改了内置的原型(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 是一种原型(prototype)语言。这意味着每个对象都由原型(prototype)对象支持。在 JavaScript 中,该原型(prototype)以四种方式之一分配:
  • 通过对象的构造函数(例如,new Foo 创建一个以 Foo.prototype 作为其原型(prototype)的对象)
  • Object.create ES5(2009)中添加的功能
  • __proto__ accessor 属性(ES2015+,仅在 Web 浏览器上,在标准化之前存在于某些环境中)或 Object.setPrototypeOf (ES2015+)
  • 在为原始对象创建对象时由 JavaScript 引擎调用,因为您正在调用它的方法(这有时称为“提升”)

  • 所以在你的例子中,因为 firstName是一个字符串原语,它被提升为 String每当你调用它的方法时的实例,以及 String实例的原型(prototype)是 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# 扩展方法之间存在一些主要区别:
  • (正如 DougR 在评论中指出的)C# 的扩展方法 can be called on null references .如果您有 string扩展方法,这段代码:
    string s = null;
    s.YourExtensionMethod();

    作品。 JavaScript 不是这样。 null是它自己的类型,以及 null 上的任何属性引用引发错误。 (即使没有,也没有原型(prototype)可以扩展到 Null 类型。)
  • (正如 ChrisW 在评论中指出的)C# 的扩展方法不是全局的。只有当代码使用扩展方法使用它们定义的命名空间时,它们才可访问。 (它们实际上是静态调用的语法糖,这就是它们在 null 上工作的原因。)在 JavaScript 中并非如此:如果您更改内置函数的原型(prototype), 会看到这种变化。全部 在您执行此操作的整个领域中的代码(领域是全局环境及其关联的内在对象等)。因此,如果您在网页中执行此操作,全部 您在该页面上加载的代码会看到更改。如果您在 Node.js 模块中执行此操作,全部 在与该模块相同的领域中加载的代码将看到更改。在这两种情况下,这就是您不在库代码中执行此操作的原因。 (Web 工作线程和 Node.js 工作线程加载在它们自己的领域中,因此它们具有与主线程不同的全局环境和不同的内在函数。但该领域仍然与它们加载的任何模块共享。)


  • ¹ IE8 确实有 Object.defineProperty ,但它只适用于 DOM 对象,而不适用于 JavaScript 对象。 String.prototype是一个 JavaScript 对象。

    关于javascript - 如何在 JavaScript 中编写扩展方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9354298/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com