JavaScript 中特定于类型的扩展方法的等价物是什么?

What's the equivalent of type-specific extension methods in JavaScript?

假设您有 class Person。它的定义如下:

function Person(name, age) {
    this.name = name;
    this.age = age;
}

现在假设你有一组 Persons(或人),你想找到最老的一个。在 C# 中,您可以通过扩展方法执行此操作:

Person Oldest(this IEnumerable<Person> people) =>
    people.OrderByDescending(p => p.Age).First();

// Usage:
var elder = people.Oldest();

JavaScript 中的等价物是什么?到目前为止,这就是我所能想到的:

Array.prototype.oldest = function() {
    return this.slice().sort(function(left, right) {
        return left.age - right.age;
    }).pop();
};

这很好用并且语法与 C# 相同,但有一些缺点:

1) 它修改了内置函数的原型,这可能会导致与这样做的其他库发生冲突。

2) 它不是类型安全的:很容易意外调用不包含人的数组,这可能导致运行时错误。

或者,您可以这样定义它:

function oldest(people) {
    // ...
}

但是你必须像 oldest(people) 那样调用它而不是 people.oldest(),这会影响可读性。

在 JavaScript 中是否有任何类型安全的语法 "nice" 方法来执行此操作?

您可以尝试不同的方法:

  • 如果您的程序中只有一个 Person 数组,您可以将方法添加为数组的一个 属性。

    var people = [person1, person2];
    people.oldest = function() {
      // Find the oldest person in this array
    };
    // ... later
    people.oldest();
    
  • 您可以将方法定义为 Person 的静态 属性,并将 Person 的数组作为参数传递:

    Person.oldest = function(people) {
       // Find the oldest person in an array
    };
    var people = [person1, person2];
    Person.oldest(people);
    
  • 扩展Array(需要ES6)

    class People extends Array {
      oldest() {
        // Find the oldest person in a People collection
      }
    }
    var people = new People();
    people.push(person1, person2);
    people.oldest();
    

因为 js 不是类型安全的,你最好将该方法实现为 oldest(people) ...

只需将其视为装饰器模式 - 一种将功能投射到一组未知的相关实体中的合法方法。

然后 - 您可以在您的函数中执行 type-checking。

你可以命名空间它使语法更"obvious"如果这是你的顾虑我猜:

personList(persons).getOldest()

作为一个 objective-c-ish 示例。

然后,您可以将 type-specific 检查添加到 personList 的创建者:

function personList(persons) {

     //iterate over persons and make sure 
     //it's valid. return undefined or {} if not. 

     return {
         getOldest: function() {
              // insert clever code here ...
              persons.slice().dice().puree();
          },
          getYoungest: function() {
             //even more clever code here ...
          }
      }

}

通过这种方法,代码

PersonList(cats).getOldest()

抛出一个 'getOldest undefined' 错误——当您有 11,000,000 行 js 代码需要整理时,这可以很容易地发现问题。

它的额外优势是让您的 c# inner-child 感觉更自在(在您的项目文件夹中有一个名为 "ArrayExtensions.Persons.js" 的 js 文件)。感觉像 "chicken soup for the c# soul," 对吧?

另一种带有排序原型的方法。 Person.prototype.ageCompare 检查参数是否是 Person 的实例,如果不是则抛出错误。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.ageCompare = function (b) {
    if (!(b instanceof Person)) {
        throw 'b is no instance of Person!';
    }
    return this.age - b.age;
};


var peoples = [new Person('Tim', 31), new Person('Jane', 32), new Person('Frank', 28), new Person('Sue', 31), new Person('Baby', 2)];
peoples.sort(function (a, b) { return a.ageCompare(b); });
document.write('<pre>' + JSON.stringify(peoples, 0, 4) + '</pre>');