在项目中80%的时间用到的ES6语法只占其20%,所以我们暂时先集中精力把这20%学好,那就差不多够用了,剩下的可以看书或是查文档,现学现用。

重要提示:教程的示例代码请前往es6-demo,下载后可以结合这个讲义进行学习操作。

1.let && const

let和const的出现让js有了块级作用域,这个块级作用域是个神器,由于之前没有块级作用域的存在,以及var关键字的变量提升,导致我们调试的时候会出现一些莫名其妙的问题,同时也是很长一段时间面试的常问问题之一。

下面看两个简单的demo理解。

// demo 1
function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

// demo 2
const PI = 3.1415;
console.log(PI); // 3.1415

PI = 3;
console.log(PI); // TypeError: "PI" is read-only

2.destructuring

destructuring是解构的意思,ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。来两个例子看看大家就明白了。

'use strict';

// 数组的解构赋值
let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo); // 1
console.log(bar); // 2
console.log(baz); // 3

// 对象的解构赋值
var { foo, bar } = { foo: "aaa", bar: "bbb" };
console.log(foo);   // "aaa"
console.log(bar );  // "bbb"

// 字符串的解构赋值
const [a, b, c, d, e] = 'hello';
console.log(a + b + c + e); // 'hello'

3.template string

let name = 'guoyongfeng';
let age = 18;

console.log(`${name} want to drink ${age}`)

4.arrow function

arrow function译名即为箭头函数,这早已不是一个新名词,下面简单看一下它的写法

class Animal {
    constructor(name){
        this.name = name;
    }
    // type = 'water'这里的意思是当type未传值的时候默认是'water'
    drink(type = 'water'){
        // 使用了箭头函数
        setInterval( () => {
            // 模板字符串
            console.log(`${this.name} want to drink ${type}`)
        }, 1000)
    }
}

let pig = new Animal('pig');

console.log(pig.drink('milk'));

export default Animal;

5.rest

我们知道JS函数内部有个arguments对象,可以拿到全部实参。现在ES6给我们带来了一个新的对象,可以拿到除开始参数外的参数,即剩余参数,听起来好屌的样子,我们来段代码。

// rest
function restFunc(a, ...rest) {
  console.log(a)
  console.log(rest)
}
restFunc(1);
restFunc(1, 2, 3, 4);

6.spread

spread为扩展操作符,来一个有点无聊的例子。

var args = ["a", "b", "c"];
console.log(...args); // "a" "b" "c"

就是这样无聊的例子,如果没有spread语法的支持,我们还得来个遍历,ES6委员会真是程序员的小棉袄。

7.class, extends, super

回想之前,如果我们需要模拟一个js的类,一般会采用构造函数加原型的方式。

function Point(x,y){
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
}

而现在我们可以使用class来定义一个类 代码清单:class.js

'use strcit';

export default class Point {
  // constructor方法是类的默认方法
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  // 这里定义的都是类的公共方法
  // 等同于Point.prototype.toString
  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

var point = new Point(2, 3);

console.log(point.toString());
console.log(point.hasOwnProperty('x'))
console.log(point.hasOwnProperty('y'))
console.log(point.hasOwnProperty('toString'))
console.log(point.__proto__.hasOwnProperty('toString'))

在moduleB中来import这个文件进行运行。 代码清单:moduleB.js

'use strict';

// import moduleA from './moduleA';
import Point from './class.js';

8.Object.assign

Object.assign用于对象的合并,ES6对object做了很多扩展,assign是最值得点评的。想必你很熟悉jquery提供的extend接口,那么ES6的Object.assign就从语法层面做了这件事情,是不是很nice。

var target = { a: 1 };

var source1 = { b: 2 };
var source2 = { c: 3 };

Object.assign(target, source1, source2);
console.log(target); // {a:1, b:2, c:3}

9.Decorator

修饰器(Decorator)是一个表达式,用来修改类的行为。这是ES7的一个提案,目前Babel(babel-plugin-transform-decorators-legacy)转码器已经支持。

不知道大家有没有使用过java的spring mvc,其中的注解就跟这个比较相似,学习React的话可以重点关注下这个语法,因为后面使用redux类库的时候会频繁的用到decorator。

首先说下如何配置babel的插件来进行decorator的解析。

// 官网提供了babel-plugin-transform-decorators这个插件来解析,但是我发现不work,就找了下面这个
$ npm install babel-plugin-transform-decorators-legacy --save-dev

配置.babelrc的plugins字段。

{
  "presets": ["es2015", "react", "stage-0"],
  "plugins": ["transform-decorators-legacy"]
}

ok,接下来来段使用decorator的示例代码

function testable(target) {
  target.isTestable = true;
}

@testable
class MyTestableClass {}

console.log(MyTestableClass.isTestable) // true

10.promise

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。

下面摘抄一个《ECMASCRIPT 6入门》书上的例子,使用promise模拟一个ajax方法的demo用于大家理解

var getJSON = function(url) {
  var promise = new Promise(function(resolve, reject){
    var client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

    function handler() {
      if ( this.readyState !== 4 ) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});

11.export, import

以前我们学习AMD和CMD规范,讨论用什么样的模块化规范比较合适,更有甚者,不得不使用UMD规范来做全兼容,现在好了,ES6在语言层面推出了模块化的写法。

新建两个模块

$ touch moduleA.js moduleB.js

代码清单:moduleA.js

'use strict';

export default function foo(x, y) {
  return x * y;
}

// 另外几种导出的方式
// function foo() {
//   console.log('foo');
// }
// export { foo as default };
// export var a = 1;
// export const PI = 3.14;

代码清单:moduleB.js

'use strict';

import moduleA from './moduleA';

console.log( moduleA(2, 3) );

代码清单:index.js

'use strict';

import moduleB from './util/moduleB ';

最终运行打印出结果:6;

结语

多的不在赘述,以上的一些知识可以当成学习ES6的一个快餐,不成体系,但是快速掌握常用的一些语法,有时间有精力建议最好买本书通读一遍。