字节面试官问:你能不能实现把对象解构到数组上?

本文详细介绍了ES6中的Iterator接口及其在for...of循环中的应用,包括数组和对象的遍历规则,以及如何通过添加Symbol.iterator属性实现对象可迭代以便于解构赋值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本文主要介绍 ES6 的 Iterator, Iterator 可以说在ES6中非常重要!是面试官经常会被问到的问题!坚持看到最后哟,后面才是重头戏!

一、for...of

在进入正题之前,我们先来了解下for...of循环的一些特性,它是ES6的标准,作为遍历所有数据结构的统一的方法。

1.遍历数组返回的是元素

const arr=[1,2,3,4]
for(let item of arr){
  console.log(item); //1 2 3 4
}

可以看到打印输出数组每一个元素。

2.不能遍历不具有 iterator 属性的数据结构

let obj={
  a:1,
  b:2,
  c:3
}
for(let item of obj){
  console.log(item); //TypeError: obj is not iterable
}

可以看到遍历输出对象的元素时会报错: obj is not iterable,也就是obj不是可迭代的

3.不能遍历到数组原型上的属性

Array.prototype.c='d'//往数组原型上挂一个属性c
const arr=[1,2,3,4]
for(let item of arr){
  console.log(item);  //1 2 3 4
}

可以看到打印输出的依旧是1 2 3 4,没有输出数组原型上的属性。

由以上我们可以知道for...of遍历具有iterator 属性的数据结构,而数组就有iterator 属性,所以可以用 for...of遍历,而对象身上没有iterator 属性所以不可以用for...of遍历(一些特例除外)。

你们可能会想iterator到底是什么东西,for...of和我们接下来要讲的iterator迭代器有什么关联吗? 请看下文!

二、iterator(迭代器)

Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环。Iterator 接口主要供for...of消费。

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。

可能会有点晕?来个例子!

37648565ce08495a95025a3dce11a05c.jpeg

我们在浏览器的控制台里输入一个数组并输出,可以看到数组里的[[Prototype]]内包含许多属性,其中就有Symbol.iterator属性。

同时我们可以注意到:Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。

看下例:

let arr=[]

// arr={
//   [Symbol.iterator]:function(){
//     return //迭代器对象
//   }
// } arr数组上有这样一个属性Symbol.iterator 外层加了[]代表此属性只可访问不可更改

b791e0cb7bb0563cc3381daa156d6715.jpeg

可以看到数组身上的Symbol.iterator属性返回的一个函数,既然是个函数就能调用:

80a18eb3cdecc0f0d3ffeb18b08f8557.jpeg

返回的是一个迭代器对象Array Iterator{}!我们打开Array Iterator{}内层:

5f84ba257d17ebdd3f6e194432e5d380.jpeg

发现里面隐式继承了next属性!我们来使用一下!

b1cab31c97b4730e58afa76f763c2e8c.jpeg

我们可以发现返回的迭代器对象内的next属性可以取到数组内的值,next属性里的value代表取到的值,done代表是否还可以next,false代表能继续next,true代表不能next,已经到底了。

字节面试题

OK,清楚了解这些后,重头戏来了!来自字节面试题的一个问题!

题目:如下所示,想让你实现输出a,b。了解解构赋值的会知道数组和对象之间直接解构是不可行的。那怎么解决呢?

let [a,b]={a:1,b:2}

console.log(a,b);//TypeError: {(intermediate value)(intermediate value)} is not iterable

解决方案:

思路: 我们知道第一行等号左边的数组[a,b]是可迭代的,右边的对象{a:1,b:2}不可迭代的。那么我们应该‘使’命的想办法让右边的对象变成是可迭代的。既然对象身上没有迭代器属性,那我们就给它加一个!

实现: 我们给对象原型上加一个Symbol.iterator属性,以此让对象具有可迭代属性。

Object.prototype[Symbol.iterator] = function(){//Symbol.iterator属性返回的是函数
  return []  //此处应该返回的是一个迭代器对象,不是[],直接{}也不可行
}
let [a,b]={a:1,b:2}

console.log(a,b); //TypeError: undefined is not a function

我们可以看到报的错不再是not iterable,而是undefined is not a function!这是因为Symbol.iteratorreturn出来的一个迭代器对象,所以这样也是不可行的。

再来,我们想数组的解构只能往数组解构,那么我们把对象转成数组,就是硬生生的把对象的值转为[1,2],也就是把值抠出来不要key,那么此时才能解构成立。所以我们现在想让对象的迭代器属性把对象变成[1,2]。利用对象Object身上的values()方法!答案揭晓!

Object.prototype[Symbol.iterator] = function(){//Symbol.iterator属性返回的是函数
  //返回一个Array类型的可迭代对象
  return Object.values(this)[Symbol.iterator]() //this指向实例对象,Object.values(this)得到的是数组
}
let [a,b]={a:1,b:2} //实例对象 相当于获得[1,2]

console.log(a,b); //1 2

tips:Object.values()---该方法返回一个给定对象自身的所有可枚举属性值的数组 。

总结

  • for...of通常用来遍历Symbol.iterator 属性的数据结构,比如数组

  • Iterator 接口主要供for...of消费

  • 默认的 Iterator 接口部署在数据结构的Symbol.iterator属性。一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”。

本篇文章就到此为止啦,由于本人经验水平有限,难免会有纰漏,对此欢迎指正。如觉得本文对你有帮助的话,欢迎点赞收藏❤❤❤,您的点赞是持续写作的动力,感谢支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值