我的程序适用于array :: forEach但不适用于for循环

时间:2018-02-06 21:27:03

标签: javascript arrays recursion foreach

请考虑以下代码。

array.forEach来电的代码。

var data = ['a', 'b',  'c'];
var all_combinations = [];

function recursiveGetAllCombinations(data_cursor = 0, combination_being_constructed = []) {

    data.forEach(function(element) {
    combination_being_constructed[data_cursor] = element;
    if(data_cursor == data.length - 1) {
        all_combinations.push(combination_being_constructed);      
    } else {
        recursiveGetAllCombinations(data_cursor + 1, combination_being_constructed.slice());
    }
  });

}

recursiveGetAllCombinations();
console.log(all_combinations);

输出

console.log正确的输出(更准确地说,几乎正确的结果,因为有冗余:每个元素重复3次 - 但不应该是这种情况,因为forEach(element)element的值从迭代更改为另一个,显然........

(27) [Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3)]
0
:
(3) ["a", "a", "c"]
1
:
(3) ["a", "a", "c"]
2
:
(3) ["a", "a", "c"]
3
:
(3) ["a", "b", "c"]
4
:
(3) ["a", "b", "c"]
5
:
(3) ["a", "b", "c"]
6
:
(3) ["a", "c", "c"]
7
:
(3) ["a", "c", "c"]
8
:
(3) ["a", "c", "c"]
9
:
(3) ["b", "a", "c"]
10
:
(3) ["b", "a", "c"]
11
:
(3) ["b", "a", "c"]
12
:
(3) ["b", "b", "c"]
13
:
(3) ["b", "b", "c"]
14
:
(3) ["b", "b", "c"]
15
:
(3) ["b", "c", "c"]
16
:
(3) ["b", "c", "c"]
17
:
(3) ["b", "c", "c"]
18
:
(3) ["c", "a", "c"]
19
:
(3) ["c", "a", "c"]
20
:
(3) ["c", "a", "c"]
21
:
(3) ["c", "b", "c"]
22
:
(3) ["c", "b", "c"]
23
:
(3) ["c", "b", "c"]
24
:
(3) ["c", "c", "c"]
25
:
(3) ["c", "c", "c"]
26
:
(3) ["c", "c", "c"]
length
:
27

相同的代码,带有for循环。

var data = ['a', 'b',  'c'];
var all_combinations = [];

function recursiveGetAllCombinations(data_cursor = 0, combination_being_constructed = []) {

    for(i = 0; i < data.length; i++) {
    combination_being_constructed[data_cursor] = data[i];
    if(data_cursor == data.length - 1) {
        all_combinations.push(combination_being_constructed);      
    } else {
        recursiveGetAllCombinations(data_cursor + 1, combination_being_constructed.slice());
    }
  }

}

recursiveGetAllCombinations();
console.log(all_combinations);

输出

(3) [Array(3), Array(3), Array(3)]
0
:
(3) ["a", "a", "c"]
1
:
(3) ["a", "a", "c"]
2
:
(3) ["a", "a", "c"]
length
:
3

我的问题

我有两个问题。

1)首先,为什么带forEach的代码每个元素显示三次?

2)第二个:为什么两个程序在显示结果方面有所不同?

1 个答案:

答案 0 :(得分:2)

问题:

重复使用相同的数组

这是因为在迭代时你不会获取数组的副本。您在递归调用中执行slice,但这还不够。当您处于最深的递归级别时,首先在数组的最后一个条目中写入“a”,将其推送到结果上,然后在相同的内存位置写入“b”。因此,您实际上更改了已推送的数据,同时又重新添加了它。现在你有两倍相同的结果。放“c”时会发生同样的情况:您更改了之前添加的两个结果。它们都是三个相同的阵列。

所以将slice(仅)应用于传递给push方法的参数:

all_combinations.push(combination_being_constructed.slice());

第二个代码不会产生太多结果

这是因为在JavaScript中,如果您没有使用varletconst关键字明确声明变量,则会声明隐式全局范围内,因此,在递归函数调用中共享。在最深的递归级别,它迭代到数组的末尾,并且递归树中待处理的所有循环现在也将退出,因为它们都共享相同的i变量。 / p>

通过在函数作用域(或块作用域)中声明i来解决此问题。使用:

for (let i = 0; i < data.length; i++) {

一种简单的方法来检测您是否意外地执行此操作是将"use strict";置于代码文件或函数的顶部,它将引发控制台错误,而不是隐式声明全局范围内的变量。