引用值(对象)是某个特定引用类型的实例。引用类型有时也被称为对象定义,它们描述了自己的对象应有的属性和方法。
@@iterator 表示可迭代字符串的每个字符// 手动使用迭代器
let message = 'abc'
let stringIterator = message[Symbol.iterator]()
console.log(stringIterator.next()) // {value:'a', done:false}
console.log(stringIterator.next()) // {value:'b', done:false}
console.log(stringIterator.next()) // {value:'c', done:false}
console.log(stringIterator.next()) // {value:undefined, done:true}
// 使用 for-of 循环访问
for (const c of 'abcde') {
console.log(c)
}
// 用解构操作解构
let message = 'abcde'
console.log([...message]) // ['a', 'b', 'c', 'd', 'e']
Object 是 ECMAScript 中最常用的类型之一,很适合存储和在应用程序之间交换数据。
构建方式:
可以通过点语法或中括号来存取属性。
const a1 = [1, 2, 3, 4]
const a2 = Array.from(a1, x => x**2)
console.log(a2) // [1, 4, 9, 16]
4. Array.of() 将一组参数转换为数组实例
function compare(value1, value2) {
return value2 - value1
}
let value = [1, 2, 3, 4, 5]
let sum = value.reduce((prev, cur, index, array) => prev + cur)
console.log(sum) // 15
键/值存储的集合类型,可通过 set 方法添加、get 和 has 查询,通过 size 属性获取键值对数量,使用 delete 和 clear 删除值。
集合数据结构,使用 new 关键字和 Set 构造函数创建,可通过给构造函数传入一个可迭代对象创建时初始化。使用 add 方法增加值,has 方法查询,size 获取元素数量,delete 和 clear 删除元素。
let arr1 = [1, 2, 3]
let arr2 = [...arr1]
迭代器模式是指可以把某些结构称为“可迭代对象”,它们实现了正式的 Iterable 接口,而且可以通过迭代器 Iterator 消费。
迭代器是按需创建的一次性对象。每个迭代器都会关联一个可迭代对象,而迭代器会暴露其可迭代对象的API。
实现 Iterable 接口要求同时具备两种能力:
在 ECMAScript中,通过以 Symbol.iterator 作为键的属性,引用一个迭代器工厂函数。调用这个工厂函数必须返回一个新迭代器。
实现 Iterator 接口的内置属性包括:
接收可迭代对象的原生语言特性包括:
上述原生语言结构会在后台调用提供的可迭代对象的这个工厂函数创建一个迭代器。
如果对象原型链上的父类实现了 Iterable 接口,那这个对象也就实现了这个接口。
实现 Iterator 接口要求提供一个 next 方法,每次成功调用都会返回一个 IteratorResult 对象,其中包含迭代器返回的下一个值,
IteratorResult 对象包含 value 和 done 两个属性。done 为布尔值,表示是否还可以调用 next 方法获取下一个值;value 为包含可迭代对象的下一个值或 undefined (done 为 true)。
需要注意的是:
class Counter {
constructor(limit) {
this.limit = limit;
}
[Symbol.iterator]() {
let count = 1
let limit = this.limit
return {
next() {
return count <= limit ?
{done: false, value: count++} :
{done: true, value: undefined}
}
}
}
}
let counter = new Counter(3)
for (let i of counter) {
console.log(i)
}
// 1
// 2
// 3
for (let i of counter) {
console.log(i)
}
// 1
// 2
// 3
可选的 return 方法用于指定在迭代器提前关闭时执行的逻辑。迭代器提前关闭可能的情况包括:
如果迭代器没有关闭,则还可以继续从上次离开的地方继续迭代。数组的迭代器是不能关闭的。
可以测试迭代器实例的 return 属性是不是函数对象来确定这个迭代器能否关闭。不能关闭的迭代器增加 return 方法并不能让其变为可关闭的。
生成器拥有在一个函数块内暂停和恢复代码执行的能力。
生成器的形式是一个函数,函数名称前加一个星号(*)表示它是一个生成器。
function* generatorFn() {}
箭头函数不能用于定义生成器函数。
调用生成器函数会产生生成器对象,默认处于暂停执行状态。生成器对象也实现了 Iterator 接口,因此具有 next() 方法。调用 next 方法会让生成器开始或恢复执行。
yield 关键字可以让生成器停止和开始执行。生成器函数在遇到 yield 之前会正常执行,遇到关键字后执行停止并保留函数作用域状态,只有在生成器对象上调用 next 方法后才能恢复执行。
function* generatorFn() {
yield 1
yield 2
yield 3
}
for (const x of generatorFn()) {
console.log(x)
}
// 1
// 2
// 3
function* generatorFn() {
return yield 'foo'
}
let g = generatorFn()
console.log(g.next()) // {done: false, value: 'foo'}
console.log(g.next('bar')) // {done: true, value: 'var'}
function* generatorFn() {
yield* [1, 2, 3]
}
for (const x of generatorFn()) {
console.log(x)
}
// 1
// 2
// 3
function* nTimes(n) {
if (n > 0) {
yield* nTimes(n - 1)
yield n - 1
}
}
for (const x of nTimes(3)) {
console.log(x)
}
// 0
// 1
// 2
class Foo {
constructor() {
this.values = [1, 2, 3]
}
* [Symbol.iterator]() {
yield* this.values
}
}
const f = new Foo()
for (const x of f) {
console.log(x)
}
// 1
// 2
// 3
return 方法会强制生成器进入停止状态。提供给 return 方法的值就是终止迭代器对象的值。
所有的生成器对象都有 return 方法,并且关闭状态后无法恢复。for-of 等内置解构会忽略关闭后生成器对象内部返回的值。
throw 方法会在暂停的时候将一个提供的错误注入到生成器对象中,如果生成器函数内部没有处理这个错误,那么生成器就会关闭;如果处理了则会跳过当前 yield 恢复执行。
如果生成器对象还没有开始执行,那么调用 throw 方法抛出的错误不会在函数内部被捕获。