javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript迭代器

JavaScript中的迭代器和可迭代对象与生成器

作者:一只小ice​​​​​​​

这篇文章主要介绍了JavaScript中的迭代器和可迭代对象与生成器,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

1. 什么是迭代器?

概念: 迭代器(iterator),是确使用户可在容器对象(container,例如链表或数组)上遍访的对象[1][2][3],设计人员使用此接口无需关心容器对象的内存分配的实现细节。
JS中的迭代器

1.1 迭代器的基本实现

思考以下代码:

let index = 0
const bears = ['ice', 'panda', 'grizzly']

let iterator = {
  next() {
    if (index < bears.length) {
      return { done: false, value: bears[index++] }
    }

    return { done: true, value: undefined }
  }
}
console.log(iterator.next()) //{ done: false, value: 'ice' }
console.log(iterator.next()) //{ done: false, value: 'panda' }
console.log(iterator.next()) //{ done: false, value: 'grizzly' }
console.log(iterator.next()) //{ done: true, value: undefined }

1.2 迭代器的封装实现

思考一下代码:

const bears = ['ice', 'panda', 'grizzly']

function createArrIterator(arr) {
  let index = 0

  let _iterator = {
    next() {
      if (index < arr.length) {
        return { done: false, value: arr[index++] }
      }

      return { done: true, value: undefined }
    }
  }
  return _iterator
}
let iter = createArrIterator(bears)

console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())

2. 什么是可迭代对象

迭代器对象和可迭代对象是一个不同的东西,虽然它们存在关联,而且面试的时候经常面这些概念,废话不多说,我们直接进入主题。

2.1 原生可迭代对象(JS内置)

2.1.1 部分for of 演示

let str = 'The Three Bears'

const bears = ['ice', 'panda', 'grizzly']

for( let text of str) {
  console.log(text) //字符串每个遍历打印
}

for( let bear of bears) {
  console.log(bear)
}
 //ice panda grizzly

2.1.2 查看内置的[Symbol.iterator]方法

const bears = ['ice', 'panda', 'grizzly']
//数组的Symbol.iterator方法
const iter = bears[Symbol.iterator]()

console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())

const nickName = 'ice'
//字符串的Symbol.iterator方法
const strIter = nickName[Symbol.iterator]()

console.log(strIter.next())
console.log(strIter.next())
console.log(strIter.next())
console.log(strIter.next())

2.2 可迭代对象的实现

let info = {
  bears: ['ice', 'panda', 'grizzly'],
  [Symbol.iterator]: function() {
    let index = 0
    let _iterator = {
       //这里一定要箭头函数,或者手动保存上层作用域的this
       next: () => {
        if (index < this.bears.length) {
          return { done: false, value: this.bears[index++] }
        }
  
        return { done: true, value: undefined }
      }
    }

    return _iterator
  }
}

let iter = info[Symbol.iterator]()
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())

//符合可迭代对象协议 就可以利用 for of 遍历
for (let bear of info) {
  console.log(bear)
}
//ice panda grizzly

2.3 可迭代对象的应用

2.4 自定义类迭代实现

class myInfo {
  constructor(name, age, friends) {
    this.name = name
    this.age = age
    this.friends = friends
  }

  [Symbol.iterator]() {
    let index = 0

    let _iterator = {
      next: () => {
        const friends = this.friends
        if (index < friends.length) {
          return {done: false, value: friends[index++]}
        }

        return {done: true, value: undefined}
      }
    }

    return _iterator
  }
}
const info = new myInfo('ice', 22, ['panda','grizzly'])

for (let bear of info) {
  console.log(bear)
}
//panda
//grizzly

3. 生成器函数

生成器是ES6新增的一种可以对函数控制的方案,能灵活的控制函数的暂停执行,继续执行等。

生成器函数和普通函数的不同

3.1 生成器函数基本实现

function* bar() {
  console.log('fn run')
}

bar()

3.2 生成器函数单次执行

function* bar() {
  console.log('fn run')
}

const generator = bar()

console.log(generator.next())
//fn run
//{ value: undefined, done: true }

3.3 生成器函数多次执行

function* bar() {
  console.log('fn run start')
  yield 100
  console.log('fn run...')
  yield 200
  console.log('fn run end')
  return 300
}

const generator = bar()

//1. 执行到第一个yield,暂停之后,并且把yield的返回值 传入到value中
console.log(generator.next())
//2. 执行到第一个yield,暂停之后,并且把yield的返回值 传入到value中
console.log(generator.next())
//3. 执行剩余代码
console.log(generator.next())

//打印结果:
//fn run start
//{done:false, value: 100}
//fn run...
//{done:false, value: 200}
//fn run end
//{done:true, value: 300}

3.4 生成器函数的分段传参

我有一个需求,既然生成器能控制函数分段执行,我要你实现一个分段传参。

思考以下代码:

function* bar(nickName) {
  const str1 = yield nickName
  const str2 = yield str1 + nickName
  return str2 + str1 + nickName
}
const generator = bar('ice')
console.log(generator.next())
console.log(generator.next('panda '))
console.log(generator.next('grizzly '))
console.log(generator.next())

// { value: 'ice', done: false }
// { value: 'panda ice', done: false }
// { value: 'grizzly panda ice', done: true }
// { value: undefined, done: true }

3.5 生成器代替迭代器

前面我们讲到,生成器是一个特殊的迭代器,那生成器必定是可以代替迭代器对象的,思考以下代码。

let bears = ['ice','panda','grizzly']

function* createArrIterator(bears) {
  for (let bear of bears) {
    yield bear
  }
}
const generator = createArrIterator(bears)
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())

其实这里还有一种语法糖的写法yield*

思考以下代码:

let bears = ['ice','panda','grizzly']

function* createArrIterator(bears) {
  yield* bears
}
const generator = createArrIterator(bears)
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())

4. 可迭代对象的终极封装

class myInfo {
  constructor(name, age, friends) {
    this.name = name
    this.age = age
    this.friends = friends
  }
  *[Symbol.iterator]() {
    yield* this.friends
  }
}
const info = new myInfo('ice', 22, ['panda','grizzly'])
for (let bear of info) {
  console.log(bear)
}

//panda
//grizzly

5. 总结

5.1 迭代器对象

5.2 可迭代对象

5.3 生成器函数

到此这篇关于JavaScript中的迭代器和可迭代对象与生成器的文章就介绍到这了,更多相关JavaScript迭代器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文