9、Iterator和for…of循环
Iterator
部署了next方法的对象,就具备了遍历器功能。next方法必须返回一个包含value和done两个属性的对象。value是当前位置的值,done表示遍历是否结束
function makeIterator(array){
var nextIndex = 0;
return{
next:function(){
return nextIndex <array.length?{value:array[nextIndex ++],done:fale}:{value:undefined,done:true
};
}
}
}
for…of循环
for(var n of it){
if(n>5)
break;
console.log(n);
}//0,1,2,3,4,5
for…of 默认是从0开始的
数组原生具备iterator接口
for…in 只能获取键名(数组的键名是 0,1,2,3….)
for…in 可以遍历一般对象的属性名
10、Generator函数
含义
Generator就是个内部状态遍历器。
Generator函数有两个特征
1、function关键字后面有个星号
2、函数体内部使用yield语句定义遍历器的每个成员,即不同的内部状态
function* helloWorldGenerator(){
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next(); //{value:'hello',done:false}
hw.next(); //{value:'world',done:false}
hw.next(); //{value:'ending',done:true}
hw.next(); //{value:undefined,done:true}
上面代码定义了一个Generator函数helloWorldGenerator,它的遍历器有两成员“hello”和“world”。调用这个函数,就会得到遍历器。
当Generator函数调用的时候,该函数并不执行,而是返回一个遍历器(可以理解成暂停执行)。以后每次调用这个遍历器的next方法,就从这个函数的头部或者上一次停下来的地方开始执行,直到遇到下一条yield语句为止,也就是说,next方法就是在遍历yield语句定义的内部状态。
Generator函数的本质是一种可以暂停执行的函数,yield语句就是暂停的标识。next方法遇到yield,就会暂停后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回对象的value属性的值
next方法的参数
yield语句本书并没有返回值,next方法可以带一个参数,该参数会被当成上一条yield语句的返回值
function* f(){
for(let i = 0 ; true ; i++){
let reset = yield i;
if(reset){ i = -1};
}
}
let g = f();
g.next()//{value:0,done:false}
g.next()//{value:1,done:false}
g.next(true)//{value:0,done:false}
当next没有参数时,yield语句总是返回undefined,当有参数“true”时,变量reset就被置为-1;
异步操作的应用
Generator函数的这种暂停执行效果,意味着可以把一步操作放进yield语句里面,等到next调用时再去执行
function* longRunningTask(){
yield step1();
yield step2();
yield step3();
//...
yield stepN();
}
scheduler( longRunningTask());
function scheduler(task){
setTimeout(function(){
if(!task.next().done){
scheduler(task);
}
},0);
}
使用一个函数,就可以按次序执行所有操作了
for…of循环可以自动遍历Generator函数,此时,不再需要调用用next方法
yield*语句
如果yield命令后面跟的是一个遍历器,则需要在yield后面加上*,表明它返回的是一个遍历器。
11、Promise对象
基本用法
Promise的好处是,可以将异步异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
var promise = new Promise(function(resolve,reject){
if(/*异步操作成功*/){
resolve(value);
}else{
rejrct(error);
}
});
promise.then(function(value){
//success
},function(value){
//failure
});
上面的代码表示,Promise构造函数,接收一个函数作为参数,该函数的两个参数分别是resolve和reject方法。如果异步操作运行成功,则用resolve方法将Promise对象的状态变为成功(即从pending变为resolved);否则将Promise状态改为失败(即从pending变为rejected)
catch方法:捕捉错误
catch方法是then(null,rejection)的别名,用于指定错误发生时的回调函数。Promise对象的错误具有“冒泡性质”,会一直向后传递,知道被捕获为止。
Promise.all方法
Promise.all方法用于将多个异步操作(或Promise对象),包装成新的Promise对象,这些异步操作都完成后,新的Promise对象状态才变成fulfilled,只要有一个异步操作失败,则其状态就是rejected
Promise.resove方法
将现有的对象转换成Promise对象。如果Promise.resove方法的对象不是一个具有then方法的对象,则返回一个新Promise对象,且它的状态是recolved
async函数
用来代替回调函数的一种方法。只要函数名之前加上async关键字,就表明该函数内部有异步操作。该异步操作应该返回一个Promse对象。前面用await关键字注明。
function timeout(ms){
return new Promise((resolve)=>{ setTimeout(resolve,ms); }); } async function asyncValue(value){ await timeout(50); return value; }
12、Class和Module
class
ES6引入了类这个概念,作为对象模板,通过class关键字可以定义类。this、super、constructor不在多说
Module的基本用法
export和import
import用于输入其他模块提供的功能,同时创造命名空间,防止函数名冲突。在一个js文件中可以通过export关键字输出变量
export var firstName = 'David';
export var lastName = 'Belle';
export var year= 1999;
等效于
var firstName = 'David';
var lastName = 'Belle';
var year= 1999;
export {firstName ,lastName ,year}
使用export定义模块后,其他js文件就可以通过import引入模块了
import{firstName ,lastName ,year} from './profile';
import关键字接收一个对象,里面指定要从其他模块中引入的变量。大括号里的变量名必须与被导入模块的变量名相同。如果想为输入的属性或方法换一个名字那么:
import{someMethod,another as NewName} from './exporter';
模块的整体加载
export除了输出变量,还可以输出方法和类
//circle.js
export function area(radius){
return Math.PI*radius * radius
}
export function circumferencr(radius){
return 2* Math.Pi*radius;
}
然后,在main.js中引入这个模块
//main.js
import{area,circumferencr} from 'circle'
或者整体导入
//main.js
module circle from 'circle';
module 后跟一个变量,表示导入模块定义在该变量上
export default语句
不想为某个方法或属性指定输入名称,可以使用export default语句。一个模块只能有一个默认方法。
模块继承
模块也可以继承。
假设有一个circleplus模块,继承了circle模块
//circleplus.js
export * from 'circle';
export var e =2.71828182846;
export default function(x){
return Math.exp(x);
}
上面的export* 表示输出circle模块的所有属性和方法。
export default 定义了定义了模块的默认方法。
可以对circle中的方法改名后再输出
export {area as circleArea } from ‘circle’;
加载上面模块的写法如下
//main.js
module math from“circleplus”;
import exp from "circleplus";
console.log(exp(math.pi));
上面的import exp表示,将circleplus中默认方法加载为exp方法