原文:Nesting For Loops in JavaScript

如果你在理解 freeCodeCamp 的 for 循环嵌套挑战时遇到困难,不要担心,我们会支持你的。

在这个问题中,你必须完成 multiplyAll() 函数,并接受一个多维数组作为参数。请记住,多维数组,有时也称为二维数组,只是一个数组的数组,例如,[[1,2], [3,4], [5,6]]

在右边的编辑器中,multiplyAll() 的定义如下:

function multiplyAll(arr) {
  var product = 1;
  // 只修改这一行下面的代码

  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

你需要完成这个函数,使其将 product 变量乘以参数 arr 的子数组中的每个数字,而参数 arr 是一个多维数组。

有很多不同的方法来解决这个问题,但我们将专注于使用 for 循环的最简单的方法。

设置你的 for 循环

因为 arr 是一个多维数组,你需要两个 for 循环:一个是遍历每个子数组,另一个是遍历每个子数组中的元素。

遍历内部数组

要做到这一点,像你在以前的挑战中所做的那样,设置一个 for 循环。

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    
  }
  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

请注意,我们在循环中使用 let 而不是 var 来声明 product。在这个挑战中,你不会注意到这两者之间的区别,但一般来说,只要有可能,使用 ES6 的 constlet 是很好的做法。你可以在这篇文章中了解更多原因。

现在将每个子数组打印到控制台:

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
  }
  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

因为你在用下面的 [[1,2],[3,4],[5,6,7]] 调用 multiplyAll(),你应该看到以下内容:

[ 1, 2 ]
[ 3, 4 ]
[ 5, 6, 7 ]

遍历每个子数组中的元素

现在你需要遍历你刚刚打印到控制台的子数组中的每个数字。

删除 console.log(arr[i]);,并在你刚才写的那个里面创建一个 for 循环。

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[i].length; j++) {
      
    }
  }
  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

记住,对于里面的循环,我们需要检查 arr[i].length,因为 arr[i] 是我们前面看的子数组之一。

现在将 arr[i][j] 打印到控制台,以查看每个元素:

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[i].length; j++) {
      console.log(arr[i][j]);
    }
  }
  // 只修改这一行下面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);
1
2
3
4
5
6
7

Finally, multiply product by every element in each of the sub-arrays:

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[i].length; j++) {
      product *= arr[i][j];
    }
  }
  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

如果你把 product 打印到控制台,你会看到每个测试案例的正确答案:

function multiplyAll(arr) {
  let product = 1;
  // Only change code below this line
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[i].length; j++) {
      product *= arr[i][j];
    }
  }
  // Only change code above this line
  console.log(product);
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);
6  // [[1], [2], [3]]
5040  // [[1, 2], [3, 4], [5, 6, 7]]
54  // [[5, 1], [0.2, 4, 0.5], [3, 9]]

仔细观察

如果你仍然不确定为什么应该写上面的代码,不要担心——你并不孤单。嵌套循环的工作很复杂,即使是有经验的开发者也会感到困惑。

在这样的情况下,在控制台打印一些更详细的内容可能会有帮助。回到你的代码中,打印 `Sub-array ${i}: ${arr[i]}` 到控制台,就在内部 for 循环之前:

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    console.log(`Sub-array ${i}: ${arr[i]}`);
    for (let j = 0; j < arr[i].length; j++) {
      product *= arr[i][j];
    }
  }
  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

在外层 for 循环中,每次迭代都要遍历 arr 中的子数组。你应该在控制台中看到这个:

Sub-array 0: 1,2
Sub-array 1: 3,4
Sub-array 2: 5,6,7

注意,我们在上面使用了模板字面量`Sub-array ${i}: ${arr[i]}`'Sub-array ' + i + ': ' + arr[i] 相同,只是写起来更容易。

现在在内部 for 循环中,打印 `Element ${j}: ${arr[i][j]}` 到控制台:

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    console.log(`Sub-array ${i}: ${arr[i]}`);
    for (let j = 0; j < arr[i].length; j++) {
      console.log(`Element ${j}: ${arr[i][j]}`);
      product *= arr[i][j];
    }
  }
  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

内层 for 循环会遍历每个子数组(arr[i])中的每个元素,所以你应该在控制台看到这个:

Sub-array 0: 1,2
Element 0: 1
Element 1: 2
Sub-array 1: 3,4
Element 0: 3
Element 1: 4
Sub-array 2: 5,6,7
Element 0: 5
Element 1: 6
Element 2: 7

i 的第一次迭代抓取第一个子数组,[1, 2]。然后,j 的第一次迭代会遍历该子数组中的每个元素:

// i is 0
arr[0] // [1, 2];

// j is 0
arr[0][0] // 1
// j is 1
arr[0][1] // 2

-----

// i is 1
arr[1] // [3, 4]

// j is 0
arr[1][0] // 3
// j is 1
arr[1][1] // 4

...

这个例子相当简单,但是如果不向控制台打印多个元素,还是很难理解 arr[i][j]

我们可以做的一个快速改进是在外层 for 循环中声明一个 subArray 变量,并将其设置为等于 arr[i]

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    const subArray = arr[i];
    for (let j = 0; j < arr[i].length; j++) {
      product *= arr[i][j];
    }
  }
  // 只修改这一行下面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

然后只要对代码做一些调整,使用新的 subArray 变量而不是 arr[i]

function multiplyAll(arr) {
  let product = 1;
  // 只修改这一行下面的代码
  for (let i = 0; i < arr.length; i++) {
    const subArray = arr[i];
    for (let j = 0; j < subArray.length; j++) {
      product *= subArray[j];
    }
  }
  // 只修改这一行上面的代码
  return product;
}

multiplyAll([[1,2],[3,4],[5,6,7]]);

这应该是你需要知道的关于多维数组和 for 循环嵌套的一切。