0
点赞
收藏
分享

微信扫一扫

JS中的迭代器、可迭代对象、生成器


迭代器

迭代器(iterator),是使用户在容器对象(container,例如链表或数组)上可以遍历访问的对象,使用该接口无需关心容器对象的内部实现细节。 

从上面定义上来看,迭代器是帮助我们对某个数据结构进行遍历的对象

迭代器本身也是一个具体的对象,只不过这个对象需要符合迭代器协议,通俗的讲就是该对象必须含有个next方法,next方法返回一个拥有done(boolean)和value(一个具体的值或undefined)两个属性的对象。迭代结束done为true,否则为false

创建迭代器 

下面我们写一个创建数组迭代器的方法 

function createArrayIterator(arr) {
let index = 0
return {
next() {
if(index < arr.length) {
return { done: false, value: arr[index++] }
} else {
return { done: true, value: undefined }
}
}
}
}

let nums = [1,2,3]
let names = ['小明', '小红', '小芳']

let numsIterator = createArrayIterator(nums)
console.log(numsIterator.next()) // { done: false, value: 1 }
console.log(numsIterator.next()) // { done: false, value: 2 }
console.log(numsIterator.next()) // { done: false, value: 3 }
console.log(numsIterator.next()) // { done: true, value: undefined }
let namesIterator = createArrayIterator(names)
console.log(namesIterator.next()) // { done: false, value: '小明' }
console.log(namesIterator.next()) // { done: false, value: '小红' }
console.log(namesIterator.next()) // { done: false, value: '小芳' }
console.log(namesIterator.next()) // { done: true, value: undefined }

将一个非可迭代对象 转化为 可迭代对象 

在这之前,我们可以提前考虑一下,为什么for of可以遍历数组而不能遍历对象,就是因为数组本身是有迭代器的,而对象则没有 

 

JS中的迭代器、可迭代对象、生成器_开发语言

 

JS中的迭代器、可迭代对象、生成器_前端_02

从上面两个示例应该就能明白了,对象中没有 iterable 迭代器,因为不可for of 遍历 

如果我们也想将一个非可迭代对象 转化为 可迭代对象 只需要在其中增加 Symbol.iterator 方法即可如下:

let info = {
name: 'wft',
age: 18,
height: 1.88,
// 增加 Symbol.iterator 方法 转为一个可迭代对象
[Symbol.iterator]() {
let values = Object.values(this)
let index = 0
let iterator = {
next() {
if(index < values.length) {
return { done: false, value: values[index++] }
} else {
return { done: true, value: undefined }
}
}
}
return iterator
}
}

let infoIterator = info[Symbol.iterator]()
console.log(infoIterator.next()) // { done: false, value: 'wft' }
console.log(infoIterator.next()) // { done: false, value: 18 }
console.log(infoIterator.next()) // { done: false, value: 1.88 }
console.log(infoIterator.next()) // { done: true, value: undefined }

for(let item of info) {
console.log(item)
}
//wft
//18
//1.88

注意:一定是 [Symbol.iterator] 规定好的,不可修改

arguements也是一个可迭代对象 

是不是迭代对象就看有没有迭代器即可 

function foo() {
console.log(arguments)
for(let item of arguments) {
console.log(item)
}
}

foo(1,2,3)

生成器 

生成器函数:

  • function 后面会跟上符号 *
  • 代码的执行可以被yield控制(类似于断点)
  • 生成器函数默认在执行时,返回一个生成器对象(并不会执行函数内部的代码)
  •  要想执行函数内部的代码,需要生成器对象调用它的next方法操作
  • 当调用next,执行内部函数代码时,当遇到yield时,就会中断执行

调用生成器函数,将返回生成器对象,但是并不会执行函数内部的代码,生成器对象中也有个next方法,调用next方法才会去执行方法内部的代码,遇到yield将终止执行 。示例如下:

// 生成器函数
function * fn() {
console.log(111)
yield
console.log(222)
yield
console.log(333)
}

// 调用生成器函数,返回生成器对象
// 注意:并没有执行fn中的代码
const generator = fn()

// 生成器也有一个 next 方法,调用next方法,将执行 fn 内部的代码,遇到 yield 将终止执行
generator.next() // 111
generator.next() // 222
generator.next() // 333

yield 叫产出,可以产出数据,也就是在 yield 后面跟上数据,那么它将会作为next方法的返回值,示例如下:

// 生成器函数
function * fn() {
// 第一次调用next方法,会执行这的代码...
yield '哈哈哈'
// 第二次调用next方法,会执行这的代码...
yield {name: 'wft', age: 18}
// 第三次次调用next方法,会执行这的代码...
}

const generator = fn()

console.log(generator.next()) // { value: '哈哈哈', done: false }
console.log(generator.next()) // { value: { name: 'wft', age: 18 }, done: false }

我们调用next方法的时候,也是可以传递参数的,那么这个参数就作为yield的返回值返回,示例如下: 

// 生成器函数
function * fn() {
let num1 = yield '哈哈哈'
console.log(num1, 'num1') // 注意这里得调用第二次next方法的时候才会执行 --- 结果:123
let num2 = yield {name: 'wft', age: 18}
console.log(num2, 'num2') // 同样这里得调用第三次next方法的时候才会执行 --- 结果:456
}

const generator = fn()

console.log(generator.next()) // { value: '哈哈哈', done: false }
console.log(generator.next(123)) // { value: { name: 'wft', age: 18 }, done: false }
console.log(generator.next(456)) // { value: undefined, done: true }

使用生成器代替上面的迭代器 

function * createArrayGenerator(arr) {
// 方式一:
for(let i = 0; i < arr.length; i++) {
yield arr[i]
}

// // 方式二:yield语法糖写法 等同于方式一
// yield * arr
}

let nums = [1,2,3]

// nums生成器对象
let numsGenerator = createArrayGenerator(nums)

console.log(numsGenerator.next()) // { value: 1, done: false }
console.log(numsGenerator.next()) // { value: 2, done: false }
console.log(numsGenerator.next()) // { value: 3, done: false }
console.log(numsGenerator.next()) // { value: undefined, done: true }

举报

相关推荐

0 条评论