最近在逛社区时,看到了一段这样的代码
1 | let a=0 |
虽然不觉惊讶,但仍然觉得循环遍历的许多细节,包括多个变种还是值得研究的。
话不多说,我们开始。
除了for循环外,还有以下一些方式:
forEach
1 | var arr = ['element1', 'element2', 'element3']; |
但是以上遍历,没有办法到某个特定条件退出。
当数组很大,没办法通过提前终止遍历来节省资源。
for in循环
1 | var arr = ['element1', 'element2', 'element3']; |
for in语句是一种精准的迭代语句,可以枚举对象的所有可枚举属性(可以使用Object.getOwnPropertyDescriptor(targetObj, attrName)
方法来查看对象的某个属性是否可枚举)。
也就是说,可以用它来遍历对象:
1 | var obj = { |
但是
1 | var father = { |
for in循环会将对象的原型属性也一并列举出来。故使用此方法去遍历对象属性的时候,需要加多一层判断:
1 | for (var attr in obj) { |
但是
1 | var str = 'a𠮷c'; |
ES5及之前处理字符串时,是以16位编码单位为基础的。
所以对于某些32位进行编码的字符,for in就处理得不是很好。
for of循环
1 | let str = 'a 𠮷 c'; |
但是for of
- 运行环境为ES6及以上版本,所以兼容性没有for in循环以及传统的操作好,如果需要考虑兼容上世纪的浏览器,就不能使用这个东西
- 只能用于遍历可迭代对象,即存在生成器方法(用于产生迭代器)的对象,如果用于遍历不可迭代对象,分分钟报错没商量。
可以通过检测对象的Symbol.iterator方法(相关内容将放在下一篇)是否为函数来判断对象是否可迭代。1
2
3
4
5
6
7
8
9
10
11
12
13
14let arr = ['a', 'b', 'c'];
// 判断其Symbol.iterator属性是否为函数
if ((typeof arr[Symbol.iterator]).toUpperCase() === 'FUNCTION') {
for (let element of arr) {
console.log(element);
}
} else {
console.log('此对象不可迭代');
}
// a
// b
// c
当然,像Array、Set、Map类型还提供了一些特殊的生成器,可以让搬砖工作者更方便的去处理其想关注的内容:
- entries() 返回一个迭代器,其返回值为键值对数组(Map集合的默认迭代器;对于Set集合,返回值数组的元素相同,即value)
- keys() 返回一个迭代器,其返回值为集合的键名(对于Set集合,此迭代器跟values迭代器返回值相同;对于数组,此迭代器返回值为索引)
- values() 返回一个迭代器,其返回值为集合的值(Array、Set集合的默认迭代器)除了JavaScript的内置对象,一些DOM标准的类型如NodeList也可以使用for of循环进行遍历:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29let arr = ['a', 'b', 'c', 'd']
let set = new Set(arr);
for (let item of set.entries()) {
console.log(item);
}
for (let item of arr.entries()) {
console.log(item);
}
// ["a", "a"] ["b", "b"] ["c", "c"] ["d", "d"] [0, "a"] [1, "b"] [2, "c"] [3, "d"]
for (let item of set.keys()) {
console.log(item);
}
for (let item of arr.keys()) {
console.log(item);
}
// a b c d 0 1 2 3
for (let item of set.values()) {
console.log(item);
}
for (let item of arr.values()) {
console.log(item);
}
// a b c d a b c d1
2
3
4
5let containers = document.querySelectorAll('.container');
for (let node of containers) {
// 搞事情专用注释
}
自定义对象的遍历
Object.keys()获取键名数组
1 | let father = { |
从上面的例子中可以看出,Object.keys()方法并不会获取对象的原型属性以及自身不可枚举属性,这个是比较符合我们的需求的
Object.getOwnPropertyNames()获取键名数组
此方法跟keys方法表现一样,所不同的是,其返回的数组包含了对象的不可枚举属性
1 | for (let key of Object.getOwnPropertyNames(instance)) { |
Object.entries()获取键值对数组
获得键值对数组
1 | for (let key of Object.entries(instance)) { |
Object.values()获取对象的属性值数组
1 | for (let key of Object.entries(instance)) { |
Object.getOwnPropertySymbols()获取Symbol属性名
如果需要遍历对象实例的Symbol类型的属性名,需要使用Object.getOwnPropertySymbols()方法:
1 | let father = { |
- 本文作者: Jambo
- 版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!