一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)

发布时间 2023-11-11 15:18:47作者: 龙陌

请问以下JS代码的执行结果是什么?

function control(x) {
  if (x == 3) throw new Error("break");
}
function foo(x = 6) {
  return {
    next: () => {
      control(x);
      return {done: !x, value: x && x--};
    }
  }
}
let x = new Object;
x[Symbol.iterator] = foo;
for (let i of x) console.log(i);

6、5、4、报错

对象x的操作其实是为了让x可以被函数foo通过for of遍历到每一个值,同时因为初始值是6所以是递减的结果,control只是做一个中断操作。

1、什么是迭代器?

迭代器是一个对象,需要满足:对象内部有方法next,next方法要求返回对象{done: true或false, value:值 }
!!!(注意区分:迭代器 和可迭代对象 是不一样的)

2、一个迭代器是如何遍历的?

const arr = ["a","b"]
// 数组默认是一个可迭代对象,就好比题目中的对象x
const iterator = arrSymbol.iterator // 拿到迭代器
console.log(iterator.next());
console.log(iterator.next());
// { value: 'a', done: false }
// { value: 'b', done: false }
// { value: undefined, done: true }

不难看出,value表示每次遍历的值,而done表示遍历是否完成。

3、for...of...补充

for... of...的使用需要是一个可迭代对象,这道题的x,也是因为是一个可迭代对象,所以才可以用的for...of
可以理解为:for..of..就是上面调用iterator.next()的语法糖,直到最后done为true表示遍历完了。...

4、什么是可迭代对象?

如果一个对象,实现了[Symbol.iterator]方法,且这个方法返回一个迭代器(这个方法就是一个生成迭代器的函数,比如题目中的foo函数)

function foo(x = 6) {
  return { // 返回一个迭代器
      next: () => {
          control(x);
          return {done: !x, value: x&&x-- };
      }
  }
}
// x成为可迭代对象
x[Symbol.iterator] = foo

5、得结果

for(let i of x) console.log(i);

既然x是可迭代对象,那他可以用for...of...进行遍历,遍历时会自动去执行foo,foo返回迭代器。
上面也说了for...of...的遍历就是:一次次的调用iterator的next,拿到value,直到next返回的done为true。

function foo(x = 6) {
  return {
    next: () => {
      control(x);
      return {done: !x, value: x && x--};
    }
  }
}

里层next函数调用的x是foo的参数x(闭包),x默认赋值为6,通过题目中的control函数可以知道,x=3的时候,就抛错,结束了。
当x=6,return{ done:!x, value: x && x--}
done为false,value是x && x--
6 && 6, &&前者为true,value结果取后者,return { done:false, value : 6},
然后x--变成5
继续。。。。最后结果
6,5,4,抛错

  1. ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内 2. throw 异常信息;中止程序抛出异常,可用于中止程序

  2. foo 是遍历器生成函数,遍历的时候遇到 throw 就中止遍历和抛出错误

  3. 还是推荐 阮一峰老师 https://es6.ruanyifeng.com/#docs/iterator