Array.prototype.reduce与一个简单的for循环,用于过滤和修改数据

时间:2015-07-02 15:39:24

标签: javascript performance

"Reducing Filter and Map Down to Reduce" by Elijah Manor概述了Array.prototype.reduce()的以下用例:

鉴于以下数据(来自链接文章):

var doctors = [
    { number: 1,  actor: "William Hartnell",      begin: 1963, end: 1966 },
    { number: 2,  actor: "Patrick Troughton",     begin: 1966, end: 1969 },
    { number: 3,  actor: "Jon Pertwee",           begin: 1970, end: 1974 },
    { number: 4,  actor: "Tom Baker",             begin: 1974, end: 1981 },
    { number: 5,  actor: "Peter Davison",         begin: 1982, end: 1984 },
    { number: 6,  actor: "Colin Baker",           begin: 1984, end: 1986 },
    { number: 7,  actor: "Sylvester McCoy",       begin: 1987, end: 1989 },
    { number: 8,  actor: "Paul McGann",           begin: 1996, end: 1996 },
    { number: 9,  actor: "Christopher Eccleston", begin: 2005, end: 2005 },
    { number: 10, actor: "David Tennant",         begin: 2005, end: 2010 },
    { number: 11, actor: "Matt Smith",            begin: 2010, end: 2013 },
    { number: 12, actor: "Peter Capaldi",         begin: 2013, end: 2013 }    
];

我们可以使用.reduce()同时修改和过滤数据,如下所示(也来自链接文章):

doctors = doctors.reduce(function(memo, doctor) {
    if (doctor.begin > 2000) { // this serves as our `filter`
        memo.push({ // this serves as our `map`
            doctorNumber: "#" + doctor.number,
            playedBy: doctor.actor,
            yearsPlayed: doctor.end - doctor.begin + 1
        });
    }
    return memo;
}, []);

但是,为什么人们更喜欢这个而不是简单的for循环呢?我怀疑它超出了具有相似内容的简单迭代循环(尽管我无法测试自Jsperf is down以来的声明)。

除了语法首选项之外,是否有任何理由(性能或其他方面)在简单循环上使用.reduce()实现?

1 个答案:

答案 0 :(得分:1)

mapreduce这样的数组操作的一个客观好处是样板代码的固有变量范围和减少。比较:

var result = 0;
for (var i = 0, length = arr.length; i < length; i++) {
    result += arr[i];
}

// vs:

var result = arr.reduce(function (acc, val) { return acc + val; }, 0);

巨型循环声明与你在这里尝试做的事情没有任何关系,它只是样板代码。此外,您的范围现在有两个额外的变量ilength浮动,没有人要求,如果您不小心,可能会或可能不会引入一些非明显的错误。

另一方面,reduce代码只包含执行所需操作所需的最少部分。在像CoffeeScript这样的东西中,它的语法甚至可以进一步简化为arr.reduce (acc, val) -> acc + val,这非常简洁。即使你需要在循环/回调中的操作期间创建额外的变量,那些不会使外部范围混乱。

其次,reduce是一个众所周知的范例,可以作为该代码块意图的良好声明。您不需要解析无用的辅助变量并弄清楚它们的用途,您可以简单地将操作分解为正在操作的数组(arr)以及回调表达式的结果(acc + val)将产生,然后在整个数组上推断出结果将是什么。

在某些情况下,编译器也可以更好地优化

潜在的这样的操作,但我认为这在实践中大多没有看到。