【问题标题】:What's the equivalent of type-specific extension methods in JavaScript?JavaScript 中特定于类型的扩展方法的等价物是什么?
【发布时间】:2016-04-22 04:33:46
【问题描述】:

假设你有一个班级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 中是否有任何类型安全、语法上“不错”的方法?

【问题讨论】:

  • 我会使用 oldest(people) 并返回最旧的 Person,既简单又安全,而且在我看来比将新属性分配给内置函数更具可读性
  • 对于最旧的,不需要排序,只需要遍历,返回最大值的集合即可。
  • 排序为n log n。 argmax 可以线性完成。只需从头到尾迭代即可。

标签: javascript arrays prototype extension-methods type-safety


【解决方案1】:

另一种带有排序原型的方法。 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>');

【讨论】:

    【解决方案2】:

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

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

    然后 - 你可以在你的函数中进行类型检查。

    如果你担心的话,你可以命名空间让语法更“明显”:

    personList(persons).getOldest()
    

    作为一个客观 c 的例子。

    然后,您可以将特定类型的检查添加到 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# 内部孩子更有宾至如归的感觉(在你的项目文件夹中有一个名为“ArrayExtensions.Persons.js”的 js 文件)。感觉就像“c# 灵魂的鸡汤”,对吧?

    【讨论】:

      【解决方案3】:

      您可以尝试不同的方法:

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

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

        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();
        

      【讨论】:

      • 嗯,我喜欢Person.oldest() 的想法。让事情更有条理。
      猜你喜欢
      • 2019-07-17
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2011-05-05
      • 2017-03-19
      • 2014-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多