跳到主要内容

Overview of ES6

· 阅读需 9 分钟
木易(OwenYang)
互联网人、电子垃圾体验者、挨踢FEer、木易跟打器作者

Slides in ES6 overview workshop

Intro

What

ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准

Goal

ES6的目标,是使得JavaScript语言可以用来编写大型的复杂的应用程序,成为企业级开发语言。 新的语言特性,代码更优雅,程序更健壮,减少不必要的重复,减少不必要的第三方依赖。

Agenda

  • template strings
  • const
  • let
  • block-level declaration
  • Destructuring Assignment
  • arrow functions
  • default function params
  • class
  • module

Requirements

Babel https://babeljs.io/docs/usage/cli/

$ npm install --global babel

Talk is cheap, show me the code.

template strings

var first = "Song"
var last = "Yang";
var name = `I'm ${first} ${last}!`;

性能对比 http://heeroluo.net/article/detail/54

它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

const

const PI = 3.14
Object.defineProperty(typeof global === "object" ? global : window, "PI", {
value: 3.14,
enumerable: true,
writable: false,
configurable: false
})

let

声明变量,变量只在let命令所在代码块内有效。

{
var a = 1;
let b = 10;
}

a //1
b // ReferenceError: b is not defined.

let不允许在相同作用域内,重复声明同一个变量。

// error
{
let a = 10;
let a = 1;
}

block-level declaration

  • let, const 块级作用域
  • var 函数作用域
function fn() {
for(var i=0,len=5;i<len;i++) {
//body
}
console.log(i,len);=> 5,5
}

ES5的JavaScript的不支持块级作用域,变量仅仅被限制到函数作用域内。

Pros

// IIFE写法
(function () {
var tmp = ...;
...
}());

// 块级作用域写法
{
let tmp = ...;
...
}

function scope

function f() { console.log('I am outside!'); }
(function () {
if(false) {
// What should happen with this redeclaration?
function f() { console.log('I am inside!'); }
}

f();
}());

Destructuring Assignment

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

Array destructuring

var a = 1;
var b = 2;
var c = 3;

var [a, b, c] = [1, 2, 3];

[a, b] = [b, a];

模式匹配(嵌套数组)

var [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

var [,,third] = ["foo", "bar", "baz"];
third // "baz"

var [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

解构失败

var [foo] = [];
var [foo] = 1;
var [foo] = 'Hello';
var [foo] = false;
var [foo] = NaN;
var [bar, foo] = [1];

foo // undefined
  • 如果对undefined或null进行解构,会报错。
// 报错
var [foo] = undefined;
var [foo] = null;
  • 解构赋值允许指定默认值。
[x, y='b'] = ['a'] // x=3, y='b'
  • 解构赋值不仅适用于var命令,也适用于let和const命令。
var [v1, v2, ..., vN ] = array;
let [v1, v2, ..., vN ] = array;
const [v1, v2, ..., vN ] = array;

Object destructuring

var { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

如果变量名与属性名不一致,必须写成下面这样。

var { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
var o = {
p: [
"Hello",
{ y: "World" }
]
};

var { p: [x, { y }] } = o;
x // "Hello"
y // "World"
  • 对象的解构也可以指定默认值。
  • 如果要将一个已经声明的变量用于解构赋值
// 错误的写法

var x;
{x} = {x:1};
// SyntaxError: syntax error

({x} = {x:1});

JavaScript引擎会将{x}理解成一个代码块,从而发生语法错误。

NOTE 数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

Pros

  • 交换变量的值
  • 从函数返回多个值
  • 遍历Map结构 配合变量的解构赋值,获取键名和键值
    for (let [key, value] of map) {
    console.log(key + " is " + value);
    }
  • 输入模块的指定方法
    const { SourceMapConsumer, SourceNode } = require("source-map");

Arrow Function

  • 语法糖:function的简写,或者是使用胖箭头 () => 的Lamda表达式。
  • 不仅仅是语法糖:自动绑定外部作用域的"this".
const items = [1, 2, 3, 4];

var double = (x) => x * 2;
var byTwo = items.map(double);
// => [2, 4, 6, 8]
var foot = {
kickNormal: function () {
this.yelp = "Ouch!";
setImmediate(function () {
console.log(this.yelp);
}.bind(this));
},
kick: function () {
this.yelp = "Ouch!";
setImmediate(() => console.log(this.yelp));
}
};

default function params

在ES6默认值特性出现前,手动处理默认值有几种方式:

function log(message, level) {
level = level || 'warning';
console.log(level, ': ', message);
}

log('low memory'); // warning: low memory
log('out of memory', 'error'); // error: out of memory

为了处理参数未传递的情况,我们常看到typeof检测:

if (typeof level == 'undefined') {
level = 'warning';
}

有时也可以检查arguments.length

if (arguments.length == 1) {
level = 'warning';
}

这些方法都可以很好的工作,但都过于手动且缺少抽象。

function log(message, level = 'warning') {
console.log(level, ': ', message);
}

log('low memory'); // warning: low memory
log('out of memory', 'error'); // error: out of memory

参数默认值使用方便且毫无违和感。

Classes

A formal inheritance syntax comes to JavaScript Really just syntactical sugar over JS prototypical inheritance

class Greeter {
constructor(msg) {
this.msg = msg;
}

static create(msg) {
return new this(msg);
}

greet() {
return `Hello ${this.msg}`;
}

set message(msg) {
this.msg = msg;
}

get message() {
return this.msg;
}

}
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

var Greeter = (function () {
function Greeter(msg) {
_classCallCheck(this, Greeter);

this.msg = msg;
}

Greeter.create = function create(msg) {
return new this(msg);
};

Greeter.prototype.greet = function greet() {
return 'Hello ' + this.msg;
};

_createClass(Greeter, [{
key: 'message',
set: function (msg) {
this.msg = msg;
},
get: function () {
return this.msg;
}
}]);

return Greeter;
})();

Extends

class FancyGreeter extends Greeter {
constructor(msg, name) {
super(msg);
this.name = name;
}

greet () {
return `${this.name}, Hello ${this.msg}`;
}
}
var fg = new FancyGreeter('World', 'Song');
console.log(fg instanceof FancyGreeter);
console.log(fg instanceof Greeter);

Module

export和import

ES6实现了模块功能,试图解决JavaScript代码的依赖和部署上的问题,取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。

export default function foo() {}
var first = 'David';
var last = 'Belle';
var year = 1973;

export {first, last, year};
import {first, last, year} from './profile';
import {first as f, last} from './profile';
import * as profile from './profile';

NOT Included

  • Map, WeakMap, Set, WeakSet
  • Promise
  • Generator
  • Iterator
  • Rest Parameter
  • Spread Operator

新的内建方法

  • Object.assign
  • [arr].find
  • "str".repeat
  • "str".startsWith
  • "str".endsWith
  • "str".includes
  • Number.isNaN
  • Number.isFinite
  • Number.isSafeInteger
  • Math.trunc
  • Math.sign

Using ES6 Today

Server

  • io 2.2.0
  • node 0.12.4

Browser

  • Browserify
  • Babel

Resources