理解JavaScript中的for/of和for/in
建议使用for/of而不使用for/in
一、for/of
for/of是ES6中定义的新循环语句,专门用于可迭代对象。数组、字符串、集合Set、映射Map是可迭代对象。
1. for/of迭代数组元素的值,不迭代数组元素的下标(数组元素是按从头到尾的顺序迭代的):
let data = [1,2,3,4,5,6,7,8,9],sum = 0
for(let element of data){
sum += element
}
console.log(sum) //=>45
2. for/of与对象
2.1 对象不可直接使用for/of:
let o={bar: 123,foo: 321}
for(let element of o){
console.log(element) //抛出TypeError,因为o不是可迭代对象
}
2.2 可通过Object.keys()和Object.values()或Object.entries()迭代对象的属性和键
2.2.1 通过Object.keys()迭代对象的属性:
let o = {x: 1,y: 2,z: 3}
let keys=""
for(let k of Object.keys(o)){
keys += k
}
console.log(keys) //"xyz"
2.2.2 通过Object.values()迭代对象的键:
let sum = 0
for(let v of Object.values(o)){
sum += v
}
console.log(sum) //6
2.2.3 通过Object.entries()和解构赋值来迭代对象的属性/键:
let pairs = ""
for(let [k,v] of Object.entries(o)){
pairs += k+v
}
console.log(pairs) //"x1y2z3"
3.for/of与字符串:
let frequency = {}
for(let letter of "mississippi"){
if(frequency[letter]){
frequency[letter]++
} else{
frequency[letter] = 1
}
}
console.log(frequency) //[m: 1,i: 4,s: 4,p: 2]
字符串是按照Unicode码点而不是UTF-16字符迭代的。
4.for/of与Set和Map
4.1 使用for/of迭代Set集合,集合中每个元素都会运行一次:
let text = "Na na na na na na na na na Batman!"
let wordSet = new Set(text.split(" ")) //wordSet:{"Na", "na", "Batman"}
let unique = []
for(let word of wordSet) {
unique.push(word)
}
console.log(unique) //["Na', "na", "Batman!"]
4.2 Map的迭代器并不迭代Map键或Map值,而是迭代键值对:
let m = new Map([[1, "one"]])
for(let [key, value] of m) {
console.log(key) //1
console.log(value) //"one"
}
二、for/in
for/in循环的in后面可以是任意对象,循环指定对象的属性名。
基本用法(将o的属性名赋值给变量p,然后打印每个属性的值):
let o = {bar: 123,foo: 321}
for(let p in o){
console.log(o[p])
//123
//321
}
三、建议使用for/of而不使用for/in
-
for/in循环并不会枚举对象的所有属性,比如它不会枚举名字为符号的属性,而对于名字为字符串的属性,它只会遍历可枚举的属性。JavaScript核心定义的各种内部方法是不可枚举的。比如,所有对象都有toString()方法,但for/in循环不会枚举toString属性。除了内部方法,内部对象的不少其他属性也是不可枚举的。
-
继承的可枚举属性也可以被for/in循环枚举。这意味着如果你使用for/in循环,并且代码中会定义被所有对象继承的属性,那你的循环就有可能出现意外结果。因此,建议使用for/of而不使用for/in。