如何用JavaScript编写扩展方法?

时间:2022-04-18 23:59:49

I need to write a few extension methods in JS. I know just how to do this in C#. Example:

我需要用JS编写一些扩展方法。我知道如何在c#中做这个。例子:

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

and then called by:

然后调用:

string firstName = "Bob";
string hi = firstName.SayHi();

How would I do something like this in JavaScript?

如何在JavaScript中实现这样的操作?

1 个解决方案

#1


103  

In that specific case, you'd assign your method to String.prototype, like this:

在这种情况下,您应该将方法赋值为String。原型,是这样的:

String.prototype.SayHi = function SayHi() {
    return "Hi " + this + "!";
};

or better as a non-enumerable property using Object.defineProperty (ES5 and higher, so basically, everything but IE8 and earlier):

或者使用objecter . defineproperty (ES5和更高的属性,基本上,除了IE8和更早的)作为不可枚举属性更好:

Object.defineProperty(String.prototype, "SayHi", {
    value: function SayHi() {
        return "Hi " + this + "!";
    }
});

JavaScript is a prototypical language. That means that every object is backed by a prototype object. In JavaScript, that prototype is assigned either by the constructor function for the object, or by the new(ish) ECMAScript5 Object.create function.

JavaScript是一种典型的语言。这意味着每个对象都有一个原型对象作为支持。在JavaScript中,原型要么由对象的构造函数分配,要么由新的(ish) ECMAScript5对象分配。创建函数。

In the former case (the constructor function), the prototype assigned to an object is defined by the prototype property of the constructor function. So if you have a constructor function called Foo:

在前一种情况(构造函数)中,分配给对象的原型由构造函数的原型属性定义。如果你有一个叫Foo的构造函数

function Foo() {
}

...then the statement

…然后声明

var f = new Foo();

...assigns Foo.prototype to the f instance as its prototype object. Thus:

…分配Foo。原型到f实例作为它的原型对象。因此:

function Foo(b) {
    this.baz = b;
}
Foo.prototype.bar = function bar() {
    console.log(this.baz);
};

var f = new Foo("Charlie");
f.bar(); // logs "Charlie"

So in your example, since firstName is a String instance (actually a string primitive, but don't worry, it gets automagically promoted to a String instance whenever necessary), its prototype is String.prototype, so adding a property to String.prototype that references your SayHi function makes that function available on all String instances.

因此,在您的示例中,由于firstName是一个字符串实例(实际上是一个字符串原语,但不必担心,它会在必要时自动升级为一个字符串实例),所以它的原型是String。原型,将属性添加到字符串中。引用SayHi函数的原型使该函数在所有字符串实例中都可用。

As DougR pointed out in a comment, one difference from C# extension methods is that C#'s extension methods can be called on null references (if you have a string extension method, string s = null; s.YourExtensionMethod(); actually works). This isn't true with JavaScript; null is its own type and there's no prototype to extend for it.

正如DougR在注释中指出的那样,c#扩展方法的一个不同之处在于,c#的扩展方法可以调用空引用(如果您有一个字符串扩展方法,字符串s = null;s.YourExtensionMethod();实际工作)。JavaScript不是这样的;null是它自己的类型,没有原型来扩展它。


A quick note about the function names in those examples, e.g.

关于这些例子中的函数名的一个简要说明,例如。

Object.defineProperty(String.prototype, "SayHi", {
    value: function SayHi() {
// HERE ------------^
        return "Hi " + this + "!";
    }
});

Foo.prototype.bar = function bar() {
// AND HERE -----------------^
    console.log(this.baz);
};

That form, where we're using a function expression with a name in it (a "named function expression," aka NFE) used to be famous for having issues (on IE8 and earlier; and on really, really old versions of a couple of other browsers). With everything else being dead and IE8 being nearly dead, there's no need to worry about NFEs anymore. (And the above would be okay even in IE8.)

这个表单,我们使用一个函数表达式,其中有一个名称(一个“命名函数表达式”,又名NFE),它曾经因为有问题而出名(在IE8和更早的版本中;在其他浏览器的老版本上)。随着其他所有东西都死了,IE8也快死了,没有必要再担心NFEs了。(即使在IE8中,上述情况也可以。)

#1


103  

In that specific case, you'd assign your method to String.prototype, like this:

在这种情况下,您应该将方法赋值为String。原型,是这样的:

String.prototype.SayHi = function SayHi() {
    return "Hi " + this + "!";
};

or better as a non-enumerable property using Object.defineProperty (ES5 and higher, so basically, everything but IE8 and earlier):

或者使用objecter . defineproperty (ES5和更高的属性,基本上,除了IE8和更早的)作为不可枚举属性更好:

Object.defineProperty(String.prototype, "SayHi", {
    value: function SayHi() {
        return "Hi " + this + "!";
    }
});

JavaScript is a prototypical language. That means that every object is backed by a prototype object. In JavaScript, that prototype is assigned either by the constructor function for the object, or by the new(ish) ECMAScript5 Object.create function.

JavaScript是一种典型的语言。这意味着每个对象都有一个原型对象作为支持。在JavaScript中,原型要么由对象的构造函数分配,要么由新的(ish) ECMAScript5对象分配。创建函数。

In the former case (the constructor function), the prototype assigned to an object is defined by the prototype property of the constructor function. So if you have a constructor function called Foo:

在前一种情况(构造函数)中,分配给对象的原型由构造函数的原型属性定义。如果你有一个叫Foo的构造函数

function Foo() {
}

...then the statement

…然后声明

var f = new Foo();

...assigns Foo.prototype to the f instance as its prototype object. Thus:

…分配Foo。原型到f实例作为它的原型对象。因此:

function Foo(b) {
    this.baz = b;
}
Foo.prototype.bar = function bar() {
    console.log(this.baz);
};

var f = new Foo("Charlie");
f.bar(); // logs "Charlie"

So in your example, since firstName is a String instance (actually a string primitive, but don't worry, it gets automagically promoted to a String instance whenever necessary), its prototype is String.prototype, so adding a property to String.prototype that references your SayHi function makes that function available on all String instances.

因此,在您的示例中,由于firstName是一个字符串实例(实际上是一个字符串原语,但不必担心,它会在必要时自动升级为一个字符串实例),所以它的原型是String。原型,将属性添加到字符串中。引用SayHi函数的原型使该函数在所有字符串实例中都可用。

As DougR pointed out in a comment, one difference from C# extension methods is that C#'s extension methods can be called on null references (if you have a string extension method, string s = null; s.YourExtensionMethod(); actually works). This isn't true with JavaScript; null is its own type and there's no prototype to extend for it.

正如DougR在注释中指出的那样,c#扩展方法的一个不同之处在于,c#的扩展方法可以调用空引用(如果您有一个字符串扩展方法,字符串s = null;s.YourExtensionMethod();实际工作)。JavaScript不是这样的;null是它自己的类型,没有原型来扩展它。


A quick note about the function names in those examples, e.g.

关于这些例子中的函数名的一个简要说明,例如。

Object.defineProperty(String.prototype, "SayHi", {
    value: function SayHi() {
// HERE ------------^
        return "Hi " + this + "!";
    }
});

Foo.prototype.bar = function bar() {
// AND HERE -----------------^
    console.log(this.baz);
};

That form, where we're using a function expression with a name in it (a "named function expression," aka NFE) used to be famous for having issues (on IE8 and earlier; and on really, really old versions of a couple of other browsers). With everything else being dead and IE8 being nearly dead, there's no need to worry about NFEs anymore. (And the above would be okay even in IE8.)

这个表单,我们使用一个函数表达式,其中有一个名称(一个“命名函数表达式”,又名NFE),它曾经因为有问题而出名(在IE8和更早的版本中;在其他浏览器的老版本上)。随着其他所有东西都死了,IE8也快死了,没有必要再担心NFEs了。(即使在IE8中,上述情况也可以。)