在循环中使用函数有什么好处?

时间:2015-12-21 18:35:27

标签: javascript loops closures

似乎功能迭代器正在替换JS中for循环的使用。

与for / while循环相比,传递mapreduce等函数有什么好处?

var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
  return num * 2;
});

var doubles = [];
for (i = 0; i < numbers.length; i++) { 
    doubles[i] = numbers[i] * 2;
}

3 个答案:

答案 0 :(得分:4)

我不知道为什么你会使用map a&#34;关闭&#34;。闭包是完全不同的东西。 map是一个高阶函数 - 定义为对函数进行操作(取或返回)的函数。这种编程风格可以被称为&#34; functional&#34;。

使用map等功能有其优点和缺点。正如一位评论者指出的那样,它更紧凑:

function sum(array) {
  var sum = 0;
  for (var i = 0; i < array.length; i++) sum += array[i];
  return sum;
}

VS

function sum(array) {
  return array.reduce(add);
}

addfunction add(a, b) { return a + b; }

更紧凑意味着更易读,更少表面积。使用名为add的函数也增强了可读性;我们可以很容易地知道操作是添加数组的元素。

基本上,所有数组函数都具有for-loop等价物,这需要设置更多变量并编写更多逻辑。例如,map

function map(array, fn) {
  var result = [];
  for (var i = 0; i < array.length; i++) result.push(fn(array[i]));
  return result;
}

这可以更加紧凑地写成array.map(fn)

在许多情况下,我们可能已经定义了要执行元素映射或元素过滤的函数。在这种情况下,我们可以简单地使用mapreduce等功能。

map及其朋友也有优势,他们对稀疏数组很友好。例如:

var a = [];
a[1000000] = 1;

现在我们将每个元素加倍:

function double(array) {
  var result = [];
  for (var i = 0; i < array.length; i++) result.push(array[i] * 2); 
  return result;
}

这循环一百万次并返回一个充满NaN的数组。相比之下

array.map(elt => elt*2)

仅对位于1000000位置的单个元素进行操作,并根据需要返回稀疏数组。

功能风格也为灵活性提供了额外的可能性。让我们说我们想要概括倍增事物的想法。我可以编写一个高阶函数来创建一个函数,该函数将某个值乘以特定因子:

function multiply(n) {
  return function(x) {
    return n * x;
  };
}

现在我可以写

array.map(multiply(2))

在循环解决方案中,这种简洁性和表达性很难实现。

forEachmap等可能比for循环慢。如果您的代码在紧密循环中运行了一百万次,这可能是一个问题。在现实世界中,它很少是一个问题。最好将代码可读性和紧凑性放在首位。

但是,没有人强迫您使用mapfilter。在ES7或其他任何调用中,您将能够使用数组理解以更可读的方式完成相同的事情:

[ for (i of array) if (i % 2) i + 1 ]

结合了过滤器和地图。

更远一点,如果你打算编写一个迭代数组的生成器,并从每个元素中产生一些计算,你将需要使用for循环,因为没有办法从内部产生forEach回调:

function *double(array) {
  for (var i = 0; i < array.length; i++) yield array[i]*2;
}

function *double(array) {
  array.forEach(elt => yield elt*2); // DOESN'T WORK!!
}

答案 1 :(得分:3)

这是一种范式转变。后者是命令式编程的一种形式,其中用户是创建计算机消耗的数据的用户。前者本质上是一种基于数学的更具功能性的方法,利用已经存在的数据(代码)。

虽然应用于当前的计算机状态,但是没有理论上的(处理)优势,但随着处理能力的提高,函数式编程变得更加有用。

功能编程允许基于数学的推理形式强调输入和输出。由于函数是一流的数据类型,JavaScript特别擅长处理这种风格

答案 2 :(得分:1)

在这里

好的答案。会随着时间的流逝而增加我要欣赏的一件事:当您以“命令式” /旧式方式进行操作时,它倾向于鼓励一种具有许多中间变量的编程风格,到处都是可变的东西,并且“当我重复执行同样的事情,我不妨对同一数据执行其他操作”,这是代码设计中的最大陷阱-牺牲关注点分离以提高可疑的性能。考虑这个例子

const numbers = [1,4,9,16];
let sum = 0;
let onlyEvenNumbers = [];
for(i = 0; i < numbers.length; i++) {
  sum += numbers[i];
  if(numbers[i] % 2 == 0) {
    onlyEvenNumbers.push(numbers[i]);
  }
}

这是糟糕的imo,因为您获得的性能(如果有)很少,并且for循环没有明确的目的。当然,在这种简单的情况下,可能还可以,但是可以很快得到真正的丑陋。同样,乍一看还不清楚onlyEvenNumbers var中存储了什么,直到您读到了for循环的底部-再次,在这里可能还可以,但是如果for循环变大,可能会造成混淆。 获胜的功能方法(还要注意,事物不仅可以是const,而且一旦构建就不会变异):

const numbers = [1,4,9,16];
const sum = numbers.reduce((acc, val) => acc + val);
const onlyEvenNumbers = numbers.filter(num => num % 2 == 0);