如何在JavaScript中使用循环

99 阅读4分钟

TLDR; 这篇文章教你JavaScript中存在的各种循环结构,以及在什么时候使用哪一种。

迭代/循环

有时候,我们有一些结构需要我们在它们之间进行循环。我们的意思是说,我们要查看该结构中的每一个项目,并对其做一些处理。下面是一些应用的领域。

  • 显示每一个项目。一个非常常见的应用是直观地显示一个列表中的每一个项目。一个常见的例子是在电子商务网站上显示购物车中的每一个项目,因此你可以看到你将要购买的东西。有许多循环结构可以帮助你显示列表中的所有内容,如for,for/in,for/of ,仅举几例。你将会在文章中进一步了解你的区别。

  • 地图映射是指迭代一个结构,并将其从一种形式变为另一种形式。当你拥有的数据还没有准备好进行下一步时,你通常想这样做。下一步可能是显示你的数据,你想从一个数据对象改变为更有表现力的东西。

  • 减少。当你减少数据时,你会从一种形式变成一种减少的形式。那么这意味着什么呢?它意味着你不再是一个订单项目的列表,而是它们减少到一些有趣的东西,例如,项目的总和。

迭代项目

为了迭代项目,有很多结构可供你使用。让我们从一个简单的for-loop 。它是以下列方式构成的。

for(<start condition>; <break condition>; <incremental phase> ) {

}

我们的想法是将一个循环定义为具有以下阶段。

  1. 开始条件。在开始条件中,你循环的值初始化为一个特定的值,例如:let i=0;

  2. 断裂条件。接下来你要定义中断条件,当满足这个条件时,将停止循环的进一步迭代,例如i< 5

  3. 递增阶段。最后,你要定义你希望循环变量在每个迭代中增加/减少多少。

一个典型的for-loop ,看起来是这样的。

for (let i =0; i < 5; i++) {

}

通常将变量命名为i ,代表索引,即循环中的当前位置。最好是给它一个更具描述性的名字,比如这样。

for (let position =0; position < cart.length; position++) {

}

注意,我使用let ,以确保我们有块的范围,这样position 在循环结束后会继续存在。var 不会给你块的范围,并在循环之外泄漏

// DON'T

for (var position =0; position < cart.length; position++) {

}

// position is still alive here

For-in

For-in 是最被误解的循环之一。我听过很多对话,人们说用 ,但不知道为什么。所以让我们解释一下这是怎么回事。for-of

For-in 列出对象的属性。让我们来看看下面的代码是什么意思。

let object = {
  name: 'chris',
  city: 'London'
};

for (let prop in object) {
  console.log(prop)
}

// name, city

当你认为你可以在一个看起来像这样的数组上使用它时,问题就发生了。

let array = [1, 2, 3];

for (let prop in array) {
  console.log(prop)
} 

// '0', '1', '2'

你得到的不是区域内的值,而是索引。如果你对此感到惊讶,你应该知道,JavaScript中的大多数东西实际上是一个对象。考虑一下下面的代码。

typeof [1,2,3] // 'object'

它告诉你,你正在处理一个对象。这意味着你的数组在引擎盖下看起来是这样的。

{
  "0": 1,
  "1": 2,
  "2": 3
}

还有一个方法对数组有类似的作用,即Object.keys() 。下面的代码产生的结果与for-in 类似。

Object.keys([1,2,3]) // ['0', '1', '2']

注意,for-inObject.keys() 有类似的应用范围,对键/属性进行操作。

获取值

如果数值是你想要的,那么你有几个选择。

Object.values([1,2,3]) // 1, 2, 3

你也可以像这样使用for-of 循环。

for(let obj of arr) {
  console.log(obj);
}

// 1,2,3

或者,你可以使用forEach() ,一个关于数组的方法,像这样。

let arr = [1,2,3];

arr.forEach((item, number, array) => console.log(item))

注意,你不能使用break 语句来停止一个使用forEach() 的迭代。如果你可能需要打破一个循环,考虑使用一个正常的for 结构。

改变数据

到目前为止,你一直在研究如何在所有的数据上进行迭代,但你还没有改变它。你可以在迭代过程中改变数据。根据你想改变数据的方式,你有两个结构体为其制作了map()reduce()

地图

map() 是数组数据结构的函数。它的想法是遍历数组中的所有项目,并将该项目改变成新的东西。这可能是你只对一个对象的某些属性感兴趣,或者你想从一个数据模型转变为更有表现力的东西,即一个视图模型

让我们看一个例子。

let heroes = [{
  name: 'Xena',
  country: 'Greece'
}, {
  name: 'Alexander the Great',
  country: 'Macedonia'
}]

let onlyTheName = heroes.map(hero => {
  return hero.name;
});

// can also be written as: let onlyTheName = heroes.map(hero => hero.name)

onlyTheName.forEach(name => console.log(name)) // ['Xena', 'Alexander the Great']

上面是一个迭代数组的例子,你可以你感兴趣的属性name

减少

reduce() 函数,就像map() 一样是在数组数据结构上。它也寻求改变每一个项目,但有一个重要的区别。reduce() 关心的是对项目进行操作,并将结果添加到先前的迭代结果中。这使得reduce() ,如果你想获得所有购物车项目的总和,或者你想将一组对象合并为一个对象,那么你可以使用它。让我们看一下这两个例子。

let arr = [1,2,3,4];
let sum = arr.reduce((prev, curr) => prev + curr, 0)
// sum: 10

上面的reduce() 方法被传递给一个回调,回调中包含prev ,即之前的结果和curr ,即数组中的当前项目。该回调最终返回prev + currreduce() 的第二个参数是一个初始值。最终的结果是10 ,所有的值都加起来。考虑一下这个第二个例子,你就会知道reduce() 到底有多强大。

let objects = [{
  name: 'Xena'
}, {
  country: 'Greece'
}]
let mergedObject = objects.reduce((prev, curr) => {
  return {
    ...prev,
    ...curr
  }
}, {})

// { name: 'Xena', country: 'Greece' }

总结

我已经表明,在JavaScript中,有相当多的循环结构供你使用。它们可以做不同的事情,正确使用它们可以使你的效率提高。既然你知道了for-in 的作用,就没有理由害怕使用它,尽管for-of 可能是你想要的东西。如果你还没有,可以考虑把map()reduce() 加入你的工具带。