ES6 新特性

ES6 新特性

var => let/const

var 是 function-scoped 的

var x = 3;
function func(randomize) {
    if (randomize) {
        var x = Math.random(); // (A) scope: whole function
        return x;
    }
    return x; // accesses the x from line A
}
func(false); // undefined

let/const 是 block-scoped 的

let x = 3;
function func(randomize) {
    if (randomize) {
        let x = Math.random();
        return x;
    }
    return x;
}
func(false); // 3

IIFE => block

ES5 使用 IIFE 限制 tmp 作用域

(function () {  // open IIFE
    var tmp = ···;
    ···
}());  // close IIFE

console.log(tmp); // ReferenceError

ES6 使用 let

{  // open block
    let tmp = ···;
    ···
}  // close block

console.log(tmp); // ReferenceError

字符串连接 => 模板变量

ES5 使用 + 号连接字符串

function printCoord(x, y) {
    console.log('('+x+', '+y+')');
}

ES6 使用 ${} 解释字符串

function printCoord(x, y) {
    console.log(`(${x}, ${y})`);
}

多行字符串

ES5 多行字符串

var HTML5_SKELETON =
    '<!doctype html>\n' +
    '<html>\n' +
    '<head>\n' +
    '    <meta charset="UTF-8">\n' +
    '    <title></title>\n' +
    '</head>\n' +
    '<body>\n' +
    '</body>\n' +
    '</html>\n';

ES6 多行字符串

const HTML5_SKELETON = `
    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    </body>
    </html>`;

function => 箭头函数

ES5 普通函数

var arr = [1, 2, 3];
var squares = arr.map(function (x) { return x * x });

ES6 引入箭头函数

const arr = [1, 2, 3];
const squares = arr.map(x => x * x);

多个返回值

for => forEach => for-of

ES5 之前的 for 循环

var arr = ['a', 'b', 'c'];
for (var i=0; i<arr.length; i++) {
    var elem = arr[i];
    console.log(elem);
}

ES5 的 forEach

arr.forEach(function (elem) {
    console.log(elem);
});

ES6 的 for-of

const arr = ['a', 'b', 'c'];
for (const elem of arr) {
    console.log(elem);
}

参数默认值

ES5 给参数设置默认值

function foo(x, y) {
    x = x || 0;
    y = y || 0;
    // ···
}

ES6 的参数默认值

function foo(x=0, y=0) {
    // ...
}

命名参数

ES5 多个参数封装为 Object

function selectEntries(options) {
    var start = options.start || 0;
    var end = options.end || -1;
    var step = options.step || 1;
    // ···
}

ES6 精简了 Object 拆封

function selectEntries({ start=0, end=-1, step=1 }) {
    // ···
}

任意个数的参数

ES5 接受多个参数

function logAllArguments() {
    for (var i=0; i < arguments.length; i++) {
        console.log(arguments[i]);
    }
}

ES6 接受多个参数

function logAllArguments(...args) {
    for (const arg of args) {
        console.log(arg);
    }
}

apply => (…)

Math.max()

ES5

> Math.max.apply(Math, [-1, 5, 11, 3])
11

ES6

> Math.max(...[-1, 5, 11, 3])
11

Array.prototype.push()

ES5

var arr1 = ['a', 'b'];
var arr2 = ['c', 'd'];

arr1.push.apply(arr1, arr2);
// arr1 is now ['a', 'b', 'c', 'd']

ES6

const arr1 = ['a', 'b'];
const arr2 = ['c', 'd'];

arr1.push(...arr2);
// arr1 is now ['a', 'b', 'c', 'd']

concat() => (…)

ES5

ar arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];

console.log(arr1.concat(arr2, arr3));
// [ 'a', 'b', 'c', 'd', 'e' ]

ES6

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

console.log([...arr1, ...arr2, ...arr3]);
// [ 'a', 'b', 'c', 'd', 'e' ]

object 常量中的 function

ES5

var obj = {
    foo: function () {
        // ···
    },
    bar: function () {
        this.foo();
    }, // trailing comma is legal in ES5
}

ES6

const obj = {
    foo() {
        // ···
    },
    bar() {
        this.foo();
    },
}

构造器 => class

基类

ES5 实现自己的构造器

function Person(name) {
    this.name = name;
}

Person.prototype.describe = function () {
    return 'Person called '+this.name;
};

ES6 使用 constructor 构造器

class Person {
    constructor(name) {
        this.name = name;
    }
    describe() {
        return 'Person called '+this.name;
    }
}

继承

ES5 模拟继承

function Employee(name, title) {
    Person.call(this, name); // super(name)
    this.title = title;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function () {
    return Person.prototype.describe.call(this) // super.describe()
           + ' (' + this.title + ')';
};

ES6 使用 extends 继承

class Employee extends Person {
    constructor(name, title) {
        super(name);
        this.title = title;
    }
    describe() {
        return super.describe() + ' (' + this.title + ')';
    }
}

自定义 error 构造器 => 继承 Error

ES5 实现自己的 Error 构造器

function MyError() {
    // Use Error as a function
    var superInstance = Error.apply(null, arguments);
    copyOwnPropertiesFrom(this, superInstance);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;

function copyOwnPropertiesFrom(target, source) {
    Object.getOwnPropertyNames(source)
    .forEach(function(propKey) {
        var desc = Object.getOwnPropertyDescriptor(source, propKey);
        Object.defineProperty(target, propKey, desc);
    });
    return target;
};

ES6 继承 Error

class MyError extends Error {
}

object 用作 map

ES5 使用 object 作为 map

var dict = Object.create(null);
function countWords(word) {
    var escapedWord = escapeKey(word);
    if (escapedWord in dict) {
        dict[escapedWord]++;
    } else {
        dict[escapedWord] = 1;
    }
}
function escapeKey(key) {
    if (key.indexOf('__proto__') === 0) {
        return key+'%';
    } else {
        return key;
    }
}

ES6 引入 Map 对象

const map = new Map();
function countWords(word) {
    const count = map.get(word) || 0;
    map.set(word, count + 1);
}

string 新的方法

  • startsWith
  • endsWith
  • includes
  • repeat

Array 新的方法

  • findIndex
  • Array.from(arguments):将 Array-like 对象转为 Array
  • arr4 = new Array(2).fill('x')

CommonJS => ES6 模块

多个 exports

CommonJS

//------ lib.js ------
var sqrt = Math.sqrt;
function square(x) {
    return x * x;
}
function diag(x, y) {
    return sqrt(square(x) + square(y));
}
module.exports = {
    sqrt: sqrt,
    square: square,
    diag: diag,
};

//------ main1.js ------
var square = require('lib').square;
var diag = require('lib').diag;

console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

ES6

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------ main1.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

单个 exports

CommonJS

//------ myFunc.js ------
module.exports = function () { /** ··· */ };

//------ main1.js ------
var myFunc = require('myFunc');
myFunc();

ES6

//------ myFunc.js ------
export default function () { /** ··· */ } // no semicolon!

//------ main1.js ------
import myFunc from 'myFunc';
myFunc();

Map、Set、WeakMap、WeakSet

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set

Promise

Promise 用于异步编程

function timeout(duration = 0) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, duration);
    })
}

var p = timeout(1000).then(() => {
    return timeout(2000);
}).then(() => {
    throw new Error("hmm");
}).catch(err => {
    return Promise.all([timeout(100), timeout(200)]);
})

Symbol

Symbol 可以用来访问对象的内部状态。

var MyClass = (function() {

  // module scoped symbol
  var key = Symbol("key");

  function MyClass(privateData) {
    this[key] = privateData;
  }

  MyClass.prototype = {
    doStuff: function() {
      ... this[key] ...
    }
  };

  return MyClass;
})();

var c = new MyClass("hello")
c["key"] === undefined

Proxy

Proxy:用于拦截、丢向虚拟化、日志记录/分析

// Proxying a normal object
var target = {};
var handler = {
  get: function (receiver, name) {
    return `Hello, ${name}!`;
  }
};

var p = new Proxy(target, handler);
p.world === 'Hello, world!';

// Proxying a function object
var target = function () { return 'I am the target'; };
var handler = {
  apply: function (receiver, ...args) {
    return 'I am the proxy';
  }
};

var p = new Proxy(target, handler);
p() === 'I am the proxy';

Unicode

码位放入 {} 就可以正确解读该字符:

// same as ES5.1
"𠮷".length == 2

// new RegExp behaviour, opt-in ‘u’
"𠮷".match(/./u)[0].length == 2

// new form
"\u{20BB7}"=="𠮷"=="\uD842\uDFB7"

// new String ops
"𠮷".codePointAt(0) == 0x20BB7

// for-of iterates code points
for(var c of "𠮷") {
  console.log(c);
}

generator

function* 返回的是一个 Generator 对象:

function* generator(i) {
  yield i;
  yield i + 10;
}

const gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 20

参考