4. 迭代
迭代是按照顺序反复多次执行一段程序,通常会有明确的终止条件。ECMAScript 6 规范新增了两个高级特性:迭代器和生成器。使用这两个特性,能够更清晰、高效、方便地实现迭代。
迭代器指任何实现Iterator接口的对象。每个迭代器都会关联一个可迭代对象,而迭代器会暴露该对象的 API。迭代器无须了解该对象的结构,只需要知道如何取得连续的值。
//实现了 Iterator 接口,但它的每个实例只能被迭代一次
class Counter {
// Counter 的实例应该迭代 limit 次
constructor(limit) {
this.count = 1;
this.limit = limit;
}
//
next() {
if (this.count <= this.limit) {
return { done: false, value: this.count++ };
} else {
return { done: true, value: undefined };
}
}
//
[Symbol.iterator]() {
return this;
}
}
//创建多个迭代器:把计数器变量放到闭包里,然后通过闭包返回迭代器
class Counter {
//
constructor(limit) {
this.limit = limit;
}
//
[Symbol.iterator]() {
let count = 1,
limit = this.limit;
return {
next() {
if (count <= limit) {
return { done: false, value: count++ };
} else {
return { done: true, value: undefined };
}
}
};
}
}
let counter = new Counter(3);
for (let i of counter) {
console.log(i);
}
// return方法,用于指定在迭代器提前关闭时执行的逻辑。可选,略。
生成器结构拥有在一个函数块内暂停和恢复代码执行的能力。其形式是一个函数,在函数名称前面加一个星号( *)表示。
调用生成器函数会产生一个生成器对象,它一开始处于暂停执行(suspended)的状态。调用next()方法会让生成器开始或恢复执行。yield
关键字可以让生成器停止和开始执行。生成器函数在遇到yield
前会正常执行。遇到后,执行则会停止,函数作用域的状态会被保留。停止执行的生成器函数只能通过在生成器对象上调用next()方法来恢复执行。
因为生成器对象实现了 Iterable 接口,而且生成器函数和默认迭代器被调用之后都产生迭代器,
所以生成器格外适合作为默认迭代器。
// 例1:
function* generatorFn() {
yield 1;
yield 2;
yield 3;
}
function* generatorFn() {
yield* [1, 2, 3];
}
//相较显式调用next()方法,把生成器对象当成可迭代对象使用起来更方便
for (const x of generatorFn()) {
console.log(x);
}
// 例2:使用`yield*`实现递归操作。
function* nTimes(n) {
if (n > 0) {
yield* nTimes(n - 1);
yield n - 1;
}
}
5. 对象、类
ECMA-262 将对象定义为一组属性的无序集合。对象的每个属性或方法都由一个名称来标识,这个名称映射到一个值(数据或函数)。
//创建自定义对象:创建 Object 的一个新实例,然后再给它添加属性和方法
let person = new Object();
person.name = "Nicholas";
person.age = 29;
person.sayName = function() {
console.log(this.name);
};
//创建自定义对象:字面量
let person = {
name: "Nicholas",
age: 29,
sayName() {
console.log(this.name);
}
};
以上两种方法创建具有同样接口的多个对象需要重复编写很多代码。
//工厂模式
function createPerson(name, age) {
let o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
console.log(this.name);
};
return o;
}
let person1 = createPerson("Nicholas", 29);
//自定义构造函数,可以确保实例被标识为特定类型
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
};
}
let person1 = new Person("Nicholas", 29);
//原型模式
属性分两种。①数据属性包含一个保存数据值的位置。值会从这个位置读取或写入。数据属性有 4个内部特性: [[Configurable]], [[Enumerable]], [[Writable]], [[Value]]。②访问器属性包含一个获取getter
函数和一个设置setter
函数,但都不是必需的。访问器属性有4个内部特性:[[Configurable]], [[Enumerable]], [[Get]], [[Set]]。
属性定义方法: Object.defineProperty(), Object.defineProperties(),
属性读取方法: Object.getOwnPropertyDescriptor(),
对象合并方法: Object.assign(),
相等判定方法: Object.is(),
语法糖:简写属性名,可计算属性,简写方法名,