yidld*语句
如果yield命令后面跟的是一个遍历器,需要在yield命令后面加上星号,表明它返回的是个遍历器。这被称为yield*语句。
在下面代码中,delegatinglterator是代理者,delegatedlterator是被代理者。由于yield* delegatedlterator语句得到的值,是一个遍历器,所以要用星号表示运行结果就是使用一个遍历器,遍历了多个Genertor函数,有递归的效果
let delegatedIterator = (function*() { yidld 'Hello!'; yield 'Bye!'; }()); let delegatingIterator = (function*() { yield 'Greetings!'; yield* delegatedIterator; yield 'Ok,bye'; }()); for(let value of delegatingIterator) { console.log(value); } //"Greetings!" //"Hello!" //"Bye!" //"Ok,bye."
预处理
es6原生提供了Promise对象。所谓Promise对象,就是代表了未来某个将要发生的事件 (通常是一个异步操作)。它的好处在于,有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象还提供了一整套完整的接口,使得可以更加容易地控制异步操作
基本用法
es6的Promise对象是一个构造函数,用来生成Promise实例。下面是Promise对象的基本用法。
下面代码表示,Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolve()方法和reject()方法。如果异步操作成功,则用resolve()方法将Promise对象的状态变为“成功”(即从pending变为resolved) ; 如果异步操作失败,则用reject()万法将状态变为“失败”(即从pending变为rejected)
var promise = new Promise(function(resolve,reject) { if(/* 异步操作成功 */) { resolve(value); } else { reject(error); } }); promese.then(function(value) { //成功 },function(value) { //失败 });
then方法
Promise.prototype.then方法返回的是一个新的Promise对象,因此可以采用链式写法。
getJSON("/posts.json").then(function(json) return json.post; }).then(function(post) { //执行后续处理 });
上面的代码使用then()方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数
如果前一个回调函数返回的是Promise对象,这时后一个回调函数就会等待该Promise对象有了运行结果,才会进一步调用。
getJSON("/post/1.json").then(function(post) return getJSON(post.commentURL); }).then(function(comments) { //对 comments 进行处理 });
这种设计使得嵌套的异步操作,可以被很容易地改写,从回调函数的“横向发展”改为“向下发展”。
catch()方法
Promise.prototype.catch()方法是Promise.prototype.then(null,rejection)的别名,用于指定发生错误时的回调函数。
getJSON("/posts.json").then(function(posts) { //JavaScript 代码 }).catch(function(error) { //处理前一个回调函数运行时发生的错误 console.log("发生错误!",error) })
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
getJSON("/post/1.json").then(function(post) { return getJSON(post.commentURL); }).then(function(comments) { //JavaScript代码 }).catch(function(error) { //处理前两个回调函数的错误 });
all和race()方法
Promise.all()万法用于将多个Promise实例,包装成一个新的Promise实例.
var p = Promise.all([p1,p2,p3]);
上面代码中,Promise.all()方法接收一个数组作为参数,p1、p2、p3都是Promise对象的实例。 (Promise.all()万法的参数不一定是数组,但是必须具有iterator接口,且返回的每个成员都是Promise实例。)
p的状态由p1、p2、p3决定,分成两种情况。
只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2p3的返回值组成一个数组,传递给p的回调函数
只要p1、p2、p3中有一个被reiected,p的状态就变成rejected,此时第一个被reiect的实例的返回值,会传递给p的回调函数
下面是一个具体的例子
//生成一个Promise对象的数组 var promises = [2,3,5,7,11,14].map(function(id){ return getJSON("/post/" + id + "json"); }); Promise.all(promises).then(function(posts) { //... }).catch(function(reason){ `//... });
Promise.race()方法同样是将多个Promise实例,包装成一个新的Promise实例
var p=Promise.race([p1,p2,p3]);
上面代码中,只要p1、p2、p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的返回值。
如果Promise.all0方法和Promise.race()方法的参数,不是Promise实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为Promise实例,再进一步处理
resolve(和reject()方法
有时需要将现有对象转为Promise对象,Promise.resolve()方法就起到这个作用
var jsPromise=Promise.resolve($.ajax("/whatever.json"));
上面代码将jQuery生成deferred对象,转为一个新的es6的Promise对象
如果Promise.resolve()方法的参数,不是具有then()方法的对象 (又称thenable对象),则返回一个新的Promise对象,且它的状态为fulfilled。
var p = Promise.resolve('Hello'); p.then(function(s) { console.log(s) }) //Hello
上面代码生成一个新的Promise对象的实例p,它的状态为fulfilled,所以回调函数会立即执行,Promise.resolve()方法的参数就是回调函数的参数
如果Promise.resolve()方法的参数是一个Promise对象的实例,则会被原封不动地返回.
Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected。Promise. reject()方法的参数reason,会被传递给实例的回调函数
var p = Promise.reject('出错了'); p.then(null,function(s){ console.log(s) })
上面代码生成一个Promise对象的实例p,状态为reiected,回调函数会立即执行
async函数
async函数是用来取代回调函数的另一种方法。只要函数名之前加上async关键字,就表明该函数内部有异步操作。该异步操作应该返回一个Promise对象,前面用await关键字注明。当函数执行时,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
下面代码是一个获取股票报价的函数,函数前面的async关键字,表明该函数将返回一个Promise对象。调用该函数时,当遇到await关键字,立即返回它后面的表达式(getStockPrice()函数) 产生的Promise对象,不再执行函数体内后面的语句。等到getStockPrice完成,再自动回到函数体内,执行剩下的语句.
async function getStockPrice(symbol,currency) { let price = await getStockPrice(symbol); return convert(price,currency); }
async函数并不属于ECMAScript 6,而是被列入了ES7,但是traceur编译器已经实现了这个功能。
类和模块
类和模块都是代码封装的基本方法,它们的主要差异在于:类可以实例化为对象,而标准模块则不能。由于标准模块的数据只有一个副本,因此当程序的一部分更改标准模块中的公共变量时,如果程序的其他任何部分随后读取该变量,都会获取同样的值。与之相反,每个实例化对象的对象数据则单独存在。另一个不同在于: 不像标准模块,类可以实现接口。
类
es5通过构造函数,定义类。ECMAScript 6开始引入Class (类) 概念。通过class关键字,可以定义类
本示例定义了一个类,类中包含一个constructor构造函数,而this关键字表示实例对象。除了构造方法,还可以自定义方法。定义方法时,前面不需要加上function保留字。
class Point { constructor(x,y) { this.x = x; this.y = y; } toString() { return '('+this.x+','+this.y+')'; } } var point = new Point(2,3); point.toString() //(2,3)
模块
es6支持模块功能,解决JavaScript代码的依赖和部署问题,取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的横块解决方案
基本用法
模块功能有两个关键字: export和import。export用于用户自定义模块,规定对外接口;import用于输入其他模块提供的功能,同时创造命名空间 (namespace) ,防止函数名冲突。
es6允许将独立的JavaScript文件作为模块,也就是说,允许一个JavaScript脚本文件调用另一个脚本文件。该文件内部的所有变量,外部无法获取,必须使用export关键字输出变量。
下面是一个JavaScript文件,里面使用export关键字输出变量
//profile.js export var frstName='David'; export var lastName='Belle'; export var year=1973;
上面是profile.js文件,ECMAScript 6将其视为一个模块,里面用export关键字输出了3个变量。
模块的整体加载
export关键字除了输出变量,还可以输出方法或类 (class)
本示例是一个circle.is文件,它输出两人方法
//circle.js export function area(radius) { return Math.PI * radius * radius; } export function circumference(radius) { return 2 * Match.PI * radius; }
然后,可以在main.js文件中引用这个模块
//main.js import {area,circumference} from 'circle'; console.log("圆面积:" + area(4)); console.log("原周长:"+ circumference(14));
export default语句
如果不想为某个属性或方法指定输入的名称,可以使用export default语句
//export-defult.js export default function foo() { console.log('foo'); }
在上面代码中,foo()方法被称为该模块的默认方法
在其他模块导入该模块时,import语句可以为默认方法指定任意名字
//import-default.js import customName form './export-default' customName(); // 'foo'
注意:一个模块只能有一个默认方法。
如果想在一条import语句中,同时输入默认方法和指定名称的变量,可以写成下面这样。
import customName, { otherMethod } from './export-default';
如果要输出默认属性,只需将值跟在export default之后即可
export default 42;
提示: export default也可以用来输出类
//MyClass.is export default class {...} import MyClass from 'MyClass' //main.is
模块继承
模块之间也可以继承.
下面示例设计一个circleplus模块,继承了circle模块。
//circlcplus.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.is module math from "circleplus";; import exp from "circleplus"; console.log(exp(math.pi));
上面代码中的“import exp”表示将circleplus模块的默认方法加载为exp方法
讲解结束感谢观看
参考自《JavaScript网页编程从入门到精通》