1.for-in
for-in是for循环的一个变体,它可以把一个对象的所有属性依次遍历出来,如:
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
alert(key); // 'name', 'age', 'city'
}
var a = ['A', 'B', 'C'];
for (var i in a) {
alert(i); // '0', '1', '2' 注意,这里的得到的结果是srting
alert(a[i]); // 'A', 'B', 'C'
}
2.for-of
for-of是ES6引入的新语法,谈到for-of,就先来谈谈ES6引入的新类型iterable,因为只有具有iterable类型的集合才可以通过新的for ... of循环来遍历。
Array、Map和Set都属于iterable类型
Map类型
Map是一组键值对的结构,具有极快的查找速度。
举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array:
var names = ['Michael', 'Bob', 'Tracy'];
var scores = [95, 75, 85];
给定一个名字,要查找对应的成绩,就先要在names中找到对应的位置,再从scores取出对应的成绩,Array越长,耗时越长。
如果用Map实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用JavaScript写一个Map如下:
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
Set类型
Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
重复元素在Set中自动被过滤:
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
3.for ... of循环和for ... in循环有何区别?
for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
当我们手动给Array对象添加了额外的属性后,for ... in循环仍然会去遍历这个新的属性:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
alert(x); // '0', '1', '2', 'name'
}
但是for...of只会循环集合的本身
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a ) {
alert(x); // 'A', 'B', 'C'
}
另外从返回结果来看,一个返回对象属性的值,一个返回对象的元素。
4.最好的解决方案
iterable有个内置方法:forEach,它接受一个匿名函数,每次迭代就自动回调该函数。
以array为例子:
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
alert(element);
});
以Set为例子,Set没有索引,所以前两个参数都是元素本身
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
alert(element);
})
以Map为例子,Map的回调函数参数依次为value、key和map本身:
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
alert(value);
});