版本 | 更新说明 | 时间 | 地点 |
---|---|---|---|
1.0 | 新增本笔记 | 2021/01/28 | 于创美办公室 |
yield
中断执行yield
实现输入输出【重点】
理解迭代
迭代器模式
生成器
使用数组进行迭代的缺点:
迭代器模式 Iterator Pattern (特指ECMAScript语义下)一个结构实现Iteratable接口,并能被一个Iterator所消费。在迭代器模式下,无需知道迭代对象的内部数据结构,只需要使用其暴露的迭代器进行迭代即可。
临时性可迭代对象可实现为生成器
可迭代协议 Iterable Protocol 迭代时自我识别的能力和产生迭代器的能力
实现可迭代协议的数据类型
map
set
arguments
NodeList
等DOM集合类型默认接受可迭代对象的原生语言支持有:
for-of
循环Array.from()
Map
的构造函数Set
的构造函数Promise.all()
接收由Promise组成的可迭代对象Promise.race()
接收由Promise组成的可迭代对象yield *
操作符let arr = ['foo', 'bar', 'baz']
// 解构赋值
let [a, b, c] = arr
log(a, b, c) // foo bar baz
// 扩展操作符
let arr2 = [...arr]
log(arr2) // [ 'foo', 'bar', 'baz' ]
迭代器 Iterator 迭代器是一种一次性对象,用于迭代与其关联的迭代对象
next()
,返回一个nextResult
对象nextResult
对象,包含value
属性和done
属性,前者是当前迭代的值,后者指示迭代结束与否,false
表示仍有值log = console.log
let arr = ['foo', 'bar', 'baz']
let iterator = arr[Symbol.iterator]()
log(iterator) // Object [Array Iterator] {}
let iteratorResult1= iterator.next()
let iteratorResult2= iterator.next()
let iteratorResult3= iterator.next()
let iteratorResult4= iterator.next()
log(iteratorResult1) // { value: 'foo', done: false }
log(iteratorResult2) // { value: 'bar', done: false }
log(iteratorResult3) // { value: 'baz', done: false }
log(iteratorResult4) // { value: undefined, done: true }
class Counter {
constructor(limit){
this.limit = limit
}
[Symbol.iterator](){
let counter = 1
let limit = this.limit
return {
next(){
return counter <= limit ? {
value: counter++, done: false }
: {
value: undefined, done: true }
}
}
}
}
let counter = new Counter(3)
for(const value of counter){
console.log(value)
}
for(const value of counter){
console.log(value)
}
/*Output:
1
2
3
1
2
3
*/
当for-of
循环遇到break
/return
/throw
提前退出时,会调用迭代器中的return()
方法(调用return()
方法不会强制关闭迭代器,所以可以在迭代器中断的地方调用next()
方法继续遍历)
⚠️书中提到
continue
也会提前退出时,这是明显错误的,continue
只会会跳过当此循环而已。
class Counter {
constructor(limit) {
this.limit = limit
}
[Symbol.iterator]() {
let counter = 1
let limit = this.limit
return {
next() {
return counter <= limit ? {
value: counter++, done: false }
: {
value: counter++, done: true }
},
return() {
console.log('return() : I am be called')
return {
value: undefined, done: true }
}
}
}
}
const counter = new Counter(3)
for (const value of counter) {
if (value === 2) {
continue
}
console.log(value)
}
// output:
// 1
// 3
for (const value of counter) {
if (value === 2) {
break
}
console.log(value)
}
(() => {
for (const value of counter) {
if (value === 2) {
return
}
console.log(value)
}
})()
// Output:
// 1
// return() : I am be called
try {
for (const value of counter) {
if (value === 2) {
throw 'Error'
}
console.log(value)
}
} catch (error) {
console.log(error)
}
// Output:
// 1
// return() : I am be called
// Error
The Generator object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.
*
// 生成器函数声明
function * generatorFn(){
}
箭头函数不能用来定义生成器
next()
方法,调用这个方法会让生成器开始或恢复执行。yield
中断执行yield
关键字可以让生成器停止和开始执行,也是生成器最有用的地方。生成器对象由生成器产生后,通过调用
next()
方法让生成器对象从suspend
状态转为执行状态,它会去执行生成器函数,在遇到yield
关键字的时候,执行yield
关键字后的语句,并将该语句的结果作为value
值封装在nextResult
对象中,作为next()
方法的返回值,此时生成器它的函数作用域的状态会被保存起来,在下次生成器对象调用next()
方法后,从yield关键字的下一条语句继续执行,如果再次遇到yield
关键字,则做相同的操作,当遇到return
或者生成器函数体执行结束后,作为next()
的返回值nextResult
对象,它的value
为return的返回值或者undefined
,它的done
为true
function* generatorFn() {
console.log('开始执行')
console.log('正常执行中...')
console.log('正常执行中...')
yield '中断执行'
console.log('恢复执行')
console.log('正常执行中...')
console.log('执行结束...')
}
const generatorObject = generatorFn()
console.log(generatorObject.next())
console.log(generatorObject.next())
/*Output
开始执行
正常执行中...
正常执行中...
{ value: '中断执行', done: false }
恢复执行
正常执行中...
执行结束...
{ value: undefined, done: true }
*/
function* generatorFn(n) {
while (n--) {
yield n
if (n === 2) {
return 'evil may cry'
}
}
}
const n = 5
let generatorObject = generatorFn(5)
for (let i = 0; i < n; i++) {
console.log(generatorObject.next())
}
/*Output:
{ value: 4, done: false }
{ value: 3, done: false }
{ value: 2, done: false }
{ value: 'evil may cry', done: true }
{ value: undefined, done: true }
*/
yield
实现输入输出yield
关键字会接受到next()
方法传递过来的值,并将其后的语句运算结果放到nextResult
对象中返回
⚠️注意,yield关键字会无法接受生成器对象第一次调用
next()
方法的值,因为它第一次调用next()
方法时启动生成器函数
function* generatorFn() {
console.log(yield 'hello')
console.log(yield 'generator')
}
const generatorObject = generatorFn()
console.log(generatorObject.next('foo'))
console.log(generatorObject.next('baz'))
console.log(generatorObject.next('qux'))
/*Output:
{ value: 'hello', done: false }
baz
{ value: 'generator', done: false }
qux
{ value: undefined, done: true }
*/
*
可以增强yield
的行为,让它能够迭代一个对象,yield *
的返回值依迭代器类型而定:
undefined
function* generatorFnA() {
for (const x of [1, 2, 3]) {
yield x
}
}
for (const x of generatorFnA()) {
console.log(x)
}
/*OutPut:
1
2
3
*/
function* generatorFnB() {
yield* [1, 2, 3]
}
for (const x of generatorFnB()) {
console.log(x)
}
/*Output:
1
2
3
*/
function* innerGeneratorFn() {
yield 'foo'
yield 'baz'
return 'qux'
}
function* outerGeneratorFn() {
console.log('iter value', yield* innerGeneratorFn())
}
for (const x of outerGeneratorFn()) {
console.log('value: ', x)
}
/*OutPut:
value: foo
value: baz
iter value qux
*/
class Foo {
constructor() {
this.value = [1, 2, 3]
}
*[Symbol.iterator]() {
yield* this.value
}
}
const f = new Foo()
for (const x of f) {
console.log(x)
}
生成器对象有两个方法可以使强制生成器进入关闭状态
return()
方法,调用此方法后就永久关闭生成器throw()
方法,该方法会在暂停的时候将一个提供的错误注入到生成器对象中,如果错误未被处理,生成器就会关闭,如果生成器内部处理了该错误,那么生成器就不会被关闭function* generatorFn() {
for (const x of [1, 2, 3]) {
try {
yield x
} catch (e) {
console.log("I am catch the ", e)
}
}
}
const generatorObject = generatorFn()
console.log(generatorObject.next())
console.log(generatorObject.throw(new Error('Wrong')))
console.log(generatorObject.next())
/*Output:
{ value: 1, done: false }
I am catch the Error: Wrong
...
{ value: 2, done: false }
{ value: 3, done: false }
*/
创建对象
new Object()
,然后再添加属性job = 'Software engineer'
let person = {
name: 'Nicholas',
age: 29,
// 增强的属性简写,原本应写为 job: job
job,
// 增强的方法简写,原本应写为sayName: function(){...}
sayName(){
console.log(this.name)
}
}
对象中的属性有两种类型
数据属性有四个特性(attribute):
[[Configurable]]
:是否可以通过delete
删除并重定义、是否可以修改它的特性、是否可以把它改为访问器属性[[Enumerable]]
[[Writable]]
[[Value]]
访问器属性只能通过Object.defineProperty()
方法进行定义:
[[Configurable]]
:是否可以通过delete
删除并重定义、是否可以修改它的特性、是否可以把它改为访问器属性[[Enumerable]]
[[Get]]
:获取函数[[Set]]
:设置函数Object.defineProperties()
Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptors()
Object.assign(targetObject, resourceObject...)
方法:将resourceObject中可枚举和自有属性赋值到targetObject中该方法执行的是浅复制(Shallow Copy)
Object.is()
const nameKey = `name`
const ageKey = `age`
const jobKey = `job`
let person = {
[nameKey]: `Matt`,
[ageKey]: 27,
[jobKey]: `Software Engineer`
}
console.log(person)
// { name: 'Matt', age: 27, job: 'Software Engineer' }