Iterator

迭代器是一个特殊的对象,有 next方法,每次返回{value:xx, done:false/true}的对象

Iterator 的作用有三个:

  • 为各种数据结构,提供一个统一的、简便的访问接口;
  • 使得数据结构的成员能够按某种次序排列
  • ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供 for…of 消费。

每一次调用 next 方法,返回一个包含 value done 两个属性的对象。其中,value 属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

  1. var it = makeIterator(['a', 'b']);
  2. it.next() // { value: "a", done: false }
  3. it.next() // { value: "b", done: false }
  4. it.next() // { value: undefined, done: true }
  5. function makeIterator(array) {
  6. var nextIndex = 0;
  7. return {
  8. next: function() {
  9. return nextIndex < array.length ?
  10. {value: array[nextIndex++], done: false} :
  11. {value: undefined, done: true};
  12. }
  13. };
  14. }

默认Iterator接口

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

Symbol.iterator 属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名 Symbol.iterator,它是一个表达式,返回 Symbol 对象的 iterator 属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内:

  1. // 对象obj是可遍历的
  2. const obj = {
  3. [Symbol.iterator] : function () {
  4. return {
  5. next: function () {
  6. return {
  7. value: 1,
  8. done: true
  9. };
  10. }
  11. };
  12. }a
  13. };

原生具备 Iterator 接口的数据结构如下:

  • Array
  • Map
  • Set
  • String
  • 函数的 arguments 对象
  • NodeList 对象
  • TypedArraya ```javascript let arr = [‘a’, ‘b’, ‘c’]; let iter = arrSymbol.iterator;

iter.next() // { value: ‘a’, done: false } iter.next() // { value: ‘b’, done: false } iter.next() // { value: ‘c’, done: false } iter.next() // { value: undefined, done: true }

  1. 有一些场景会默认调用 Iterator 接口:
  2. - 解构赋值
  3. - 扩展运算符
  4. - yield* 后面跟的是一个可遍历的结构
  5. - 其他:
  6. - for...of
  7. - Array.from()
  8. - Map(), Set(), WeakMap(), WeakSet()(比如`new Map([['a',1],['b',2]])`
  9. - Promise.all()
  10. - Promise.race()
  11. ```javascript
  12. let myIterable = {
  13. [Symbol.iterator]: function* () {
  14. yield 1;
  15. yield 2;
  16. yield 3;
  17. }
  18. };
  19. [...myIterable] // [1, 2, 3]

遍历方法对比

普通for

  • 只能遍历数组, 不能遍历对象

forEach

  • 无法遍历对象
  • 不能提前结束循环
  • 对元素进行判断可以使用: every() some() find() findIndex()
  • forEach会跳过空元素 如[1,,2]

for-of

  • 可中断循环
  • 不能遍历对象

for-in

  • for in 可用于遍历数组和对象, 输出的是数组的索引和对象的key,
  • 一般用于遍历对象,迭代非Symbol类型的可枚举属性

    先遍历出整数属性(integer properties,按照升序),然后其他属性按照创建时候的顺序遍历出来。

break continue return 性能(ms)
for 终止 ✔️ 跳出本次循环✔️ 终止循环✔️ 2.42
forEach ❌ ️报错 ❌报错 跳出当前的循环 3.12
for-of ✔️ ✔️ ✔️ 6.33
for-in ✔️ ✔️ 跳出当前的 循环

JavaScript 常用的循环遍历你会几种?

遍历对象

  • for-in
  • Object.keys()、Object.value()、Object.entries()
  • Object.getOwnPropertyNames() :所有的可枚举的属性值,不包括 Symbol
  • Object.getOwnPropertySymbols() : 所有 Symbol 属性名,包括不可枚举
  • Reflect.ownKeys() : 包含对象自身的所有属性,包括Symbol,包括不可枚举
  1. let obj = {name:"abc", age:24, job:"程序员"};
  2. for(let key in obj){
  3. console.log(key); //name,age,job
  4. }
  5. for (const key of Object.keys(obj)) {
  6. console.log(key, obj[key])
  7. }
  8. for (const value of Object.values(obj)) {
  9. console.log(value)
  10. }
  11. for (const [key, value] of Object.entries(obj)) {
  12. console.log(key, value)
  13. }