Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterator #22

Open
YBFACC opened this issue Jun 26, 2020 · 0 comments
Open

Iterator #22

YBFACC opened this issue Jun 26, 2020 · 0 comments

Comments

@YBFACC
Copy link
Owner

YBFACC commented Jun 26, 2020

遍历器

遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作

平常使用的(...)扩展运算符for...of... 都在隐式的调用的 Iterator

原生具备 Iterator 接口。

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

已经存在的Symbol.iterator具有以下特性

属性 True/False
writable false
enumerable false
configurable false

自己实现一个Iterator

let obj = {
  data: [1, 2, 3],
  [Symbol.iterator]: function () {
    let context = this
    let index = 0
    let length = this.data.length
    return {
      next: function () {
        if (index < length) {
          return { value: context.data[index++], done: false }
        } else {
          return { value: void 0, done: true }
        }
      }
    }
  }
}

for (const item of obj) {
  console.log(item)//1 2 3
}

原本你不可以直接在对象上使用for...of... 。现在我们在对象上定义[Symbol.iterator],使得for...of... 可以找到 iterator属性进行遍历。

for...of...

for...of... 可以约等于以下代码:

let iterator = obj[Symbol.iterator]()
let result = iterator.next()
while (!result.done) {
  console.log(result.value)
  //....
  result = iterator.next()
}

覆盖原有的Symbol.iterator

我们不可以更改对象原型链上的 Symbol.iterator ,只能在当前对象上定义新的 Symbol.iterator

例如以下例子:

let a = [1, 2, 3]

a[Symbol.iterator] = function () {
  let conext = this
  let index = 0
  return {
    next() {
      if (Number.isInteger(conext[index])) {
        return { value: conext[index++] + 1, done: false }
      } else {
        return { value: void 0, done: true }
      }
    }
  }
}
for (const item of a) {
  console.log(item)//2 3 4
}

扩展运算符

扩展运算符也是调用 Symbol.iterator

let a = [1, 2, 3]

a[Symbol.iterator] = function () {
  let conext = this
  let index = 0
  return {
    next() {
      if (Number.isInteger(conext[index])) {
        return { value: conext[index++] + 1, done: false }
      } else {
        return { value: void 0, done: true }
      }
    }
  }
}
let b = [...a] //[2,3,4]

return()和 throw()

return() 用于循环提前结束的情况。

return方法必须返回一个对象,这是 Generator 规格决定的。

let a = [1, 2, 3]

a[Symbol.iterator] = function () {
  let conext = this
  let index = 0
  return {
    next() {
      if (Number.isInteger(conext[index])) {
        return { value: conext[index++] + 1, done: false }
      } else {
        return { value: void 0, done: true }
      }
    },
    return() {
      console.log('提前结束')
      return { value: void 0, done: true }
    }
  }
}
for (const item of a) {
  console.log(item)
  break
}
for (const item of a) {
  console.log(item)
  throw new Error()
}

throw() 用于配合 Generator 函数使用。

var g = function* () {
  try {
    yield 123
  } catch (e) {
    console.log('内部捕获', e)
  }
}

var i = g()
console.log(i.next())

try {
  i.throw('a')
  i.throw('b')
} catch (e) {
  console.log('外部捕获', e)
}

关于String的补充

let a = 'abc'
for (const item of a) {
  console.log(item)
}
//a b c

这里的string是字面量,本身没有Symbol.iterator,这里应该是隐式字面量转化为String包装类,包装类上就有Symbol.iterator,符合预期。

let a = 'abc'
let A = new String(a)
for (const item of A) {
  console.log(item)
}
//a b c

参考

引用和部分代码都来自:ECMAScript 6 入门

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant