- <!-- 加载Traceur编译器 -->
- <scriptsrc="http://google.github.io/traceur-compiler/bin/traceur.js" type="text/javascript"></script>
- <!-- 将Traceur编译器用于网页 -->
- <scriptsrc="http://google.github.io/traceur-compiler/src/bootstrap.js" type="text/javascript"></script>
- <!-- 打开实验选项,否则有些特性可能编译不成功 -->
- <script>
- traceur.options.experimental =true;
- </script>
- <scripttype="module">
- classCalc{
- constructor(){
- console.log('Calc constructor');
- }
- add(a, b){
- return a + b;
- }
- }
- var c =newCalc();
- console.log(c.add(4,5));
- </script>
注意,script标签的type属性的值是module(或者traceur),而不是text/javascript。这是Traceur编译器识别ES6代码的标识,编译器会自动将所有type=module的代码编译为ES5,然后再交给浏览器执行。
2.新增关键字
(1)let是ES6中新增关键字。它的作用类似于var,用来声明变量,但是所声明的变量,只在let命令所在的代码块内有效。
(2)const 声明的是常量,一旦声明,值将是不可变的。const 的特点:
3.新增方法
(1)是否包含字符串
(2)重复字符串repeat()
repeat()返回一个新字符串,表示将原字符串重复n次。
(3)模版字符串
模板字符中,支持字符串插值:
- let first ='world';
- let last='中国';
- document.write(`Hello ${first} ${last}!`);
- // Hello world 中国!
(4)String.row()
若使用String.raw 作为模板字符串的前缀,则模板字符串可以是原始(raw)的。反斜线也不再是特殊字符,\n 也不会被解释成换行符:
- let raw =String.raw`Not a newline: \n`;
- document.write(raw ==='Not a newline: \\n');// true
(5)isFinite(),isNaN(),isInteger()
在Number对象上,新提供了Number.isFinite()和Number.isNaN()两个方法,用来检查Infinite和NaN这两个特殊值
Number.isInteger()用来判断一个值是否为整数。需要注意的是,在JavaScript内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值。
(6)Math对象新增方法
注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。
Symbol类型的值不能与其他类型的值进行运算,会报错。但是,Symbol类型的值可以转为字符串。
(4). Proxy 内置的一个代理工具,使用他可以在对象处理上加一层屏障, new Proxy() 表示生成一个Proxy实例,它的target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。var array = [1, 2, 3];//传统写法 array.forEach(function(v, i, a) {console.log(v);}); //ES6 array.forEach(v = > console.log(v));
上面三点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。
(1).Set结构实例的属性:
(2).操作方法:
(3).遍历方法:
8.Map
Map 是一个“超对象”,其 key 除了可以是 String 类型之外,还可以为其他类型(如:对象),他的方法和 Set 差不多:
9.Iterator遍历器
遍历器(Iterator)就是统一的接口机制,来处理所有不同的数据结构。
Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
Iterator的遍历过程:
每一次调用next方法,都会返回当前成员的信息,具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
遍历器返回的指针对象除了具有next方法,还可以具有return方法和throw方法。其中,next方法是必须部署的,return方法和throw方法是否部署是可选的。
return方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句或continue语句),就会调用return方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法。
throw方法主要是配合Generator函数使用,一般的遍历器用不到这个方法。
Generator函数是一个函数的内部状态的遍历器(也就是说,Generator函数是一个状态机)。形式上,Generator函数是一个普通函数,但是有两个特征。
总结一下,调用Generator函数,返回一个部署了Iterator接口的遍历器对象,用来操作内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
yield语句本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。
for...of循环可以自动遍历Generator函数,且此时不再需要调用next方法。注意:一旦next方法的返回对象的done属性为true,for...of循环就会中止,且不包含该返回对象,所以return语句返回的对象,不包括在for...of循环之中。
Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。使用指针对象的 throw 方法抛出的错误,可以被函数体内的 try ... catch 代码块捕获。这意味着,出错的代码与处理错误的代码,实现了时间和空间上的分离,这对于异步编程无疑是很重要的。
11.Promise
所谓Promise,就是一个对象,用来传递异步操作的消息。
Promise对象有以下两个特点:
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
Promise也有一些缺点:
Promise对象是一个构造函数,用来生成Promise实例
- //创建promise
- var promise =newPromise(function(resolve, reject){
- // 进行一些异步或耗时操作
- if(/*如果成功 */){
- resolve("Stuff worked!");
- }else{
- reject(Error("It broke"));
- }
- });
- //绑定处理程序
- promise.then(function(result){
- //promise成功的话会执行这里
- document.write(result);// "Stuff worked!"
- },function(err){
- //promise失败会执行这里
- document.write(err);// Error: "It broke"
- });
Promise实例具有then方法,也就是说,then方法是定义在原型对象,作用是为Promise实例添加状态改变时的回调函数。
then方法两个参数:
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
- getJSON("/posts.json").then(function(json){
- return json.post;
- }).then(function(post){
- // ...
- });
上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
- getJSON("/posts.json").then(function(posts){
- // ...
- }).catch(function(error){
- // 处理前一个回调函数运行时发生的错误
- document.write('发生错误!', error);
- });
getJSON方法返回一个Promise对象,如果该对象状态变为Resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为Rejected,就会调用catch方法指定的回调函数,处理这个错误。
- var promise =newPromise(function(resolve, reject){
- thrownewError('test')
- });
- promise.catch(function(error){ document.write(error)});
- // Error: test
上面代码中,Promise抛出一个错误,就被catch方法指定的回调函数捕获。
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
- getJSON("/post/1.json").then(function(post){
- return getJSON(post.commentURL);
- }).then(function(comments){
- // some code
- }).catch(function(error){
- // 处理前面三个Promise产生的错误
- });
上面代码中,一共有三个Promise对象:一个由getJSON产生,两个由then产生。它们之中任何一个抛出的错误,都会被最后一个catch捕获。
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决定,分成两种情况。
Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例。
- var p =Promise.race([p1,p2,p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数。
如果Promise.all方法和Promise.race方法的参数,不是Promise实例,就会先调用Promise.resolve方法,将现有对象转为Promise对象,如果Promise.resolve方法的参数,不是具有then方法的对象(又称thenable对象),则返回一个新的Promise对象,且它的状态为Resolved。
- var p =Promise.resolve('Hello');
- p.then(function(s){
- document.write(s)
- });
- // Hello
由于字符串Hello不属于异步操作(判断方法是它不是具有then方法的对象),返回Promise实例的状态从一生成就是Resolved,所以回调函数会立即执行。
Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。
- var p =Promise.reject('出错了');
- p.then(null,function(s){
- document.write(s)
- });// 出错了
上面代码生成一个Promise对象的实例p,状态为rejected,回调函数会立即执行。
12.Generator函数与Promise结合
使用Generator函数管理流程,遇到异步操作的时候,通常返回一个Promise对象。
- function getFoo (){
- returnnewPromise(function(resolve, reject){
- resolve('foo');
- });
- }
- var g =function*(){
- try{
- var foo =yield getFoo();
- document.write(foo);
- }catch(e){
- document.write(e);
- }
- };
- function run (generator){
- var it = generator();
- function go(result){
- if(result.done)return result.value;
- return result.value.then(function(value){
- return go(it.next(value));
- },function(error){
- return go(it.throw(value));
- });
- }
- go(it.next());
- }
- run(g);
上面代码的Generator函数g之中,有一个异步操作getFoo,它返回的就是一个Promise对象。函数run用来处理这个Promise对象,并调用下一个next方法。
13.Class
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
- //定义类
- classPoint{
- constructor(x, y){
- this.x = x;
- this.y = y;
- }
- toString(){
- return'('+this.x+', '+this.y+')';
- }
- }
上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
(1).class的继承
Class之间可以通过extends关键字,实现继承。子类会继承父类的属性和方法。
- classColorPointextendsPoint{
- constructor(x, y, color){
- this.color = color;// ReferenceError
- super(x, y);
- this.color = color;// 正确
- }
- }
注意:ColorPoint继承了父类Point,但是它的构造函数必须调用super方法,super方法必须放在第一行。
在Class内部可以使用get和set关键字,对某个属性设置存值函数和取值函数。
(2).class的静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。父类的静态方法,可以被子类继承。
(3).new.target属性
new是从构造函数生成实例的命令。ES6为new命令引入了一个new.target属性,(在构造函数中)返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。
(4).修饰器
修饰器(Decorator)是一个表达式,用来修改类的行为。这是ES7的一个提案,目前Babel转码器已经支持。修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,修饰器能在编译阶段运行代码。
- function testable(target){
- target.isTestable =true;
- }
- @testable
- classMyTestableClass{}
- console.log(MyTestableClass.isTestable)// true
上面代码中,@testable就是一个修饰器。它修改了MyTestableClass这个类的行为,为它加上了静态属性isTestable。
基本上,修饰器的行为就是下面这样。
- @decorator
- class A {}
- // 等同于
- class A {}
- A = decorator(A)|| A;
修饰器函数可以接受三个参数,依次是目标函数、属性名和该属性的描述对象。后两个参数可省略。testable函数的参数target,就是所要修饰的对象。如果希望修饰器的行为,能够根据目标对象的不同而不同,就要在外面再封装一层函数。
- function testable(isTestable){
- returnfunction(target){
- target.isTestable = isTestable;
- }
- }
- @testable(true)classMyTestableClass(){}
- document.write(MyTestableClass.isTestable)// true
- @testable(false)classMyClass(){}
- document.write(MyClass.isTestable)// false
如果想要为类的实例添加方法,可以在修饰器函数中,为目标类的prototype属性添加方法。
- function testable(target){
- target.prototype.isTestable =true;
- }
- @testable
- classMyTestableClass(){}
- let obj =newMyClass();
- document.write(obj.isTestable)// true
14.模块(module)
模块功能主要由两个命令构成:export和import。
ES6允许将独立的JS文件作为模块,允许一个JavaScript脚本文件调用另一个脚本文件。ES6支持多重加载,即所加载的模块中又加载其他模块。
import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
module命令可以取代import语句,达到整体输入模块的作用。module命令后面跟一个变量,表示输入的模块定义在该变量上。
为加载模块指定默认输出,使用export default命令。其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
上面代码的import命令,可以用任意名称指向export-default.js输出的方法。需要注意的是,这时import命令后面,不使用大括号。