【问题标题】:Why is .reduce used instead of reduce()? In flattening an array of arrays with JavaScript为什么使用 .reduce 而不是 reduce()?在使用 JavaScript 扁平化数组中
【发布时间】:2014-10-18 03:05:24
【问题描述】:

这个例子来自http://eloquentjavascript.net/code/#5.1。 我的问题是第一个重点细节;其他可能是有用的细节,但也是额外的;另请参阅第一个短程序以了解我的问题。

- 为什么使用arrays.reduce() 而不是reduce(arrays())。我知道他们与arrays.reduce 一起工作,但为什么呢?

这是对有用评论的回答,但对原始问题的补充。

  • 我的问题是关于第一个程序。由于它使用arrays.reduce, reduce 将是一种数组方法,我不确定为什么 reduce 是一种 数组的方法。原因可能在于设计决策 JavaScript?谢谢@cookie 怪物的评论!

这是与我的问题有关的程序-

var arrays = [[1, 2, 3], [4, 5], [6]];

console.log(arrays.reduce(function(flat, current) {
  return flat.concat(current);
}, []));

// → [1, 2, 3, 4, 5, 6]

以下这些细节是额外的,但可能(或可能不会)有用:

我知道使用了末尾的[],因为它是函数reduce 中的开始参数,以便将其他数组添加到该空数组中。我知道.concat+ 之类的两个数组与字符串放在一起,但用于数组。下面是 reduce 函数的样子,尽管它是标准的,但它的样子:

function reduce(array, combine, start){
  var current = start;
  for(var i = 0; i < array.length; i++)
    current = combine(current, array[i]);
  return current;
}

如果有帮助的话,他们的其他示例之一展示了我使用单个数组的方式。它看起来像:

console.log(reduce([1, 2, 3, 4], function(a, b){
  return a + b;
}, 0));
//  10

谢谢! :)

【问题讨论】:

  • 因为它是所有阵列的标准方法?我不完全确定你在问什么。
  • array.reduce() 已经存在。没有必要将其重新定义为全球性的。
  • 你想知道数组是如何找到它的方法的吗?还是您在询问 JavaScript 语言的设计决策?
  • 我认为combine 应该使用第三个参数array 来调用array.reduce() btw。
  • @JavaScriptArray - .reduce() 专门用于对数组进行操作。没有数组是没有用的。因此,在经典的面向对象设计中,将其作为数组对象的方法是有意义的。在面向对象的设计中,您将方法放在它们所操作的对象上,而不是制作一个巨大的全局函数列表,这些函数必须传递它们所处理的数据类型。以面向对象的方式组织功能有很多好处,而 Javascript 选择利用这些好处。

标签: javascript arrays flatten


【解决方案1】:

JavaScript 受到语言Scheme 的影响,Lisp 的方言。在 Scheme 中,higher order functions 是语言的 key 组件/功能。事实上,reduce 函数几乎等同于 Scheme 中的 fold 函数。以 JavaScript 中的 reduce 函数为例,该语言的创建者注意到程序员经常需要以某种方式遍历数组,并为程序员提供了一个 higher order 函数,他们可以在其中传入一个函数来指定他们想要如何操作数据。拥有高阶函数允许程序员抽象冗余代码,从而创建更短、更简洁、更易读的代码。

您可以在 JavaScript 中使用 reduce 函数来做许多除展平列表之外的事情。看here 一个例子。

【讨论】:

    【解决方案2】:

    在面向对象的设计中,指导原则是创建或声明对象,并且这些对象具有一系列对特定类型对象进行操作的方法。由于 Javascript 是一种面向对象的语言,其内置函数遵循许多面向对象的原则。

    .reduce() 是一个只对数组进行操作的函数。没有要操作的数组是没有用的。因此,在面向对象的设计范例中,将 .reduce() 函数作为方法放在 Array 对象上是完全有意义的。

    与全局 reduce() 函数相比,这种面向对象的方法具有以下优势:

    1. 它与该语言其他地方使用的面向对象原则一致。
    2. 使用array.reduce() 可以很方便地在特定的array 上调用.reduce() 函数,并且从它正在操作的数组的语法中可以看出。
    3. 所有数组操作都被分组为 Array 对象上的方法,从而使 API 定义更加自我记录。
    4. 如果您尝试执行 obj.reduce()(在非数组上调用它),您将立即收到有关未定义 .reduce() 方法的运行时错误。
    5. 在全局范围内不占用额外空间(例如,未定义额外的全局符号 - 减少意外覆盖或与其他代码冲突的机会)。

    如果您想知道为什么有人使用全局 reduce() 代替,您需要了解一点 Javascript 演变的历史。在 ES5 之前(或者对于运行像 IE8 等尚未实现 ES5 的浏览器的用户),Javascript 在 Array 对象上没有内置的 .reduce() 方法。然而,一些熟悉其他语言的此类有用迭代功能的开发人员希望在自己的 Javascript 或自己的 Javascript 框架中使用它。

    当您想为现有的内置对象(如 Javascript 中的 Array)添加一些功能时,您通常有两种选择。您可以向原型添加一个方法(以面向对象的方式),也可以创建一个将Array 作为其第一个参数的全局函数。

    特别是对于Array 对象,在Array 原型中添加可迭代方法存在一些潜在问题。这是因为如果任何代码对数组进行这种类型的迭代(迭代数组的一种不好的方法,但仍然有很多人这样做):

    for (var prop in array)
    

    它们最终不仅会迭代数组的元素,还会迭代数组的任何可迭代属性。如果使用这种语法将新方法分配给原型:

    Array.prototype.myMethod = function() {}
    

    然后,这个新方法最终将使用for (var prop in array) 语法进行迭代,并且经常会导致问题。

    因此,与其向原型中添加新方法,更安全的替代方法是仅使用全局函数并避免此问题。

    从 ES 5.1 开始,有一种方法可以使用 Object.defineProperty() 向对象或原型添加不可迭代的方法,因此对于较新的浏览器,现在可以向原型添加不受上述问题影响的方法更多。但是,如果您想支持旧版浏览器(如 IE8)并使用 reduce() 类型的功能,您仍然会受到这些古老的限制。

    所以...尽管全局 reduce() 不太面向对象并且在 Javascript 中通常不那么理想,但出于合法的安全/互操作性原因,一些较旧的代码会走这条路。幸运的是,随着旧版 IE 的使用量下降,我们正在把这条路抛在身后(感谢上帝,微软放弃了对 XP 的支持,最终加速了旧版 IE 的消亡)。而较新的浏览器已经内置了array.reduce()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-08
      • 2021-12-28
      • 2021-07-12
      • 1970-01-01
      • 1970-01-01
      • 2014-09-30
      • 2021-10-01
      • 2020-01-07
      相关资源
      最近更新 更多