for...in 和 for...of的使用

Yaurora

在ES中,遍历数据的时候会用到for…in/of的语法,比较一下两者的用法

for…of

for…of是ES6的语法,用来遍历可迭代的对象(含有Symbol.iterator属性的对象)。像Array, Map, Set, 字符串等

简单使用

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
const arr1 = ['a', 'b', 'c']
for(const item of arr1){
console.log(item) // a b c
}

const map1 = new Map()
map1.set('k1', 'v1')
map1.set('k2', 1)
map1.set('k3', {'name': 'kobe'})

for(const item of map1){
console.log(item) // ['k1', 'v1'] ['k2', 1] ['k3', {"name": "kobe"}]
// const [k, v] = item
// console.log(k, v)
}

const set1 = new Set()
set1.add('hello')
set1.add(100)
set1.add({'name': 'kobe'})
const obj = {eat: () => {console.log('eat')}}
set1.add(obj)

for(const item of set1){
console.log(item) // hello 100 {'name':'kobe'} {eat: () => {console.log('eat')}}
}

手动实现forOf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const forOf = (obj, cb) => {
let iterable, result
console.log(obj, typeof obj[Symbol.iterator])
if(typeof obj[Symbol.iterator] !== 'function'){
throw new TypeError('params is not a iterable')
}

iterable = obj[Symbol.iterator]()
result = iterable.next()

while(!result.done){
cb && cb(result.value)
result = iterable.next()
}
}

forOf([1,2,3], (item) => {console.log(item)})

实现遍历普通对象

由于普通对象没有Symbol.iterator属性,故不能使用for…of, 若要使用,则需要先处理

使用Object扩展方法 Object.keys()、Object.values()、Object.entries()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const obj = {
name: 'kobe',
age: 18,
friends: [
{
name: 'james'
}
]
}

// 返回普通对象的键名组成的数组
for(const item of Object.keys(obj)){
console.log(item) // name age friends
}

// 返回普通对象的键值组成的数组
for(const item of Object.values(obj)){
console.log(item) // kobe 18 [{name: 'james'}]
}

// 返回普通对象的键名键值组成的二维数组
for(const item of Object.entries(obj)){
console.log(item) // ['name', 'kobe'] ['age', 18] ['friends', [{'name': 'james'}]]
}
生成器函数重新包装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const obj = {
name: 'kobe',
age: 18,
friends: [
{
name: 'james'
}
]
}

function* entries(obj) {
for(let key of Object.keys(obj)){
yield [key, obj[key]]
}
}

for(const item of entries(obj)){
console.log(item) // ['name', 'kobe'] ['age', 18] ['friends', [{'name': 'james'}]]
}

在对象上添加Symbol.iterator属性
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
29
30
const obj = {
name: 'kobe',
age: 18,
friends: [
{
name: 'james'
}
]
}

obj[Symbol.iterator] = function(){
const keys = Object.keys(this)
let i = 0
return {
// 这里如果需要使用外卖的作用域this, 需要使用箭头函数
next: () => {
let value = undefined, done = true
if (i < keys.length){
value = this[keys[i]]
done = false
i = i + 1
}
return {value, done}
}
}
}

for(const item of obj){
console.log(item)
}

for…in

for…in是ES5的语法,用于遍历可枚举的对象,包括原型

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
29
30
31
const obj = {
name: 'kobe',
age: 18,
friends: [
{
name: 'james'
}
]
}

for(const key in obj){
console.log(key, '->', obj[key]) // name -> kobe age -> 18 friends -> [{'name': 'james'}}]
}

const obj2 = [1, 2, 3]

for(const key in obj2){
console.log(key, '->', obj2[key]) // 0 - > 1 1 -> 2 2 -> 3
}

Array.prototype.a = 123
for(const key in obj2){
console.log(key, '->', obj2[key]) // 0 - > 1 1 -> 2 2 -> 3 a -> 123
}

// 不获取原型链上的属性
for(const key in obj2){
if (obj2.hasOwnProperty(key)){
console.log(key, '->', obj2[key]) // 0 - > 1 1 -> 2 2 -> 3
}
}

小结

for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值

for in总是得到对象的key或数组、字符串的下标

for of总是得到对象的value或数组、字符串的值

for...of不能遍历普通Object对象

  • 标题: for...in 和 for...of的使用
  • 作者: Yaurora
  • 创建于 : 2023-03-10 15:23:08
  • 更新于 : 2023-03-11 01:05:37
  • 链接: https://jingyu.life/2023/03/10/node/for-in-of/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。