ES2015 (ES6)

ECMAScript (European Computer Manufacturers Association Script) 2015

用 let 和 const 代替 var

let 和 const 是 block {} 作用域,而 var 是函数。

var 的问题见 http://jinglei.me/javascript-functions/

Use arrow functions as lambdas,注意 this 指针

ES2015 之前:

function Clock() {  
    this.currentTime = new Date()
}

Clock.prototype.start = function() {  
    var self = this
    setInterval(function() {
        self.currentTime = new Date()
    }, 1000)
}

使用 ES2015:

function Clock() {  
    this.currentTime = new Date()
}

Clock.prototype.start = function() {  
    setInterval(() => {
        this.currentTime = new Date();
    }, 1000)
}

但是不是所有情况都可以使用 arrow function:

RPC.methods.sum = (a, b) => {  
  if (!this.userId) {
    throw new Error("Unauthorized");
  }
  return a + b;
}

const total = RPC.call('sum', 10, 20);  
console.log('Total is: ' + total);  

这里会抛出 this.userId is not defined

对象字面量新方式
const name = 'Tom'  
const age = 10

const user = {name, age} //相当于 {name: name, age:age}  
const {userName, userAge} = user;  
解析对象新方式
function printName({name}) {  
    console.log('Name is: ' + name);
}

const user = {  
    name: 'Tom',
    age: 18,
    city: 'Sydney'
};
printName(user);

function printUser({name, age = 18}) {  
    console.log('Name is: ' + name + ' Age: ' + age);
}
Spread arrays

ES2015 之前:

function sum(a, b) {  
    return a + b;
}

function sumAndLog(a, b) {  
    var result = sum(a, b);
    console.log('Result is: ' + result);
    return result;
}

sumAndLog(10, 20);  

使用 ES2015:

function sum(a, b) {  
    return a + b;
}

function sumAndLog(...args) {  
    const result = sum(...args);
    console.log('Result is: ' + result);
    return result;
}

sumAndLog(10, 20);  
克隆和合并对象

使用 ES2015 之前:

var user = {name: "Arunoda"};  
var newUser = _.clone(user);  
var withAge = _.extend(user, {age: 20});  
var newUserVersion = _.defaults({age: 80}, user);

console.log(newUser, withAge, newUserVersion);  

使用 ES2015 之后:

const user = {name: "Arunoda"};  
const newUser = {...user};  
const withAge = {...user, age: 20};  
const newUserVersion = {age: 80, ...user};

console.log(newUser, withAge, newUserVersion);  

但是注意,这些都是一种浅拷贝:

const user = {  
  name: 'Arunoda',
  emails: ['hello@arunoda.io']
};

const newUser = {...user};  
newUser.emails.push('mail@arunoda.io');

console.log(user.emails);  

最后输出 ["hello@arunoda.io", "mail@arunoda.io"],因为不是深拷贝,里面的元素还是指向同一的对象。

要深度拷贝 deep copy,可以参照 https://www.npmjs.com/package/deepcopy

克隆数组

const marks = [10, 20, 30];  
const newMarks = [...marks, 40];

console.log(marks, newMarks);  
Template Literals 合并字符串, 支持模板和多行

注意不是 single quote 而是 ` back-tick (grave accent 重音符)

const name = "Tom";  
const welcome = `Hello ${name}, Good day!`;

const message = `  
  # Title

  This is a multi line string as markdown.
  It's pretty nice.
`;
class 关键字
class Vehicle {  
  constructor(type, number) {
    this.type = type;
    this.number = number;
  }

  display() {
    return `Number: ${this.number}`;
  }
}

const v1 = new Vehicle('Car', 'GH-2343');  
console.log(v1.display());  

扩展、继承类

class Car extends Vehicle {  
  constructor(number) {
    super('Car', number);
  }

  display() {
    const value = super.display();
    return `Car ${value}`;
  }
}

const v1 = new Car('GH-2343');  
console.log(v1.display());  
module

和 CommonJS (Node.js) 不同, ES2015 module 不能在运行时 import

let router;

if (typeof window === 'function') {  
  router = import './client-router';
} else {
  router = import './server-router';
}

上面这段不会工作。

const sum = (a, b) => {  
    return a + b;
}
export sum; //不行  
export default sum //yes, import 时不需要 {}  
export const num = sum //yes  
Promise

异步函数库。就像它名字的意思(promise 许诺),promise 是代表一个未来会出现的值

var wait1000 = () => new Promise(  
  (resolve, reject) => { setTimeout(resolve, 1000) }
)

wait1000()  
  .then(() => {
    console.log('Yay!')
    return wait1000()
  })
  .then(() => { console.log('Wheeyee!') });
Map + Set + WeakMap + WeakSet

新的数据结构

  • 两种集合 weakset 和 set 的区别是 weakset 只能存放对象(null 会被当做 undefined)。weak 的意思是弱引用,就是当没有其他变量引用该对象,这个对象会被垃圾回收机制回收,所以 weakset 的成员无法被引用,无法遍历,weakset 只有 add、delete 和 has 三个方法,没有 size 属性,也没有 forEach 方法。Weakset 可以用来存储 DOM 节点,这样移除 DOM 时就不用担心内存泄露。

  • 两种键值对 weakmap 和 map 的区别是 weakmap 的 key 只能是非空对象,而 map 可以是 primitive type。JavaScript 一共有 6 种 primitive type: string, number, boolean, null, undefined, symbol。和 weakset 类似,如果作为 weakmap 的 key 的对象没有其他引用,那么这对值就会被当做垃圾回收。weakmap 同样不能被遍历。所以如果你需要 keys 的列表的话,使用 map。

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

// Weak Sets
var ws = new WeakSet();  
ws.add({ data: 42 });

// 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 的主要作用当 weakmap、weakset 是全局对象时候,局部作用域的对象作为 keys 或者集合的内容在离开局部作用域后,他们会被垃圾回收机制回收,这样可以更合理的使用内存。一个例子

forOf
for (let x of [1, 2, 3]) {  
  sum += x;
}

Based on https://tutor.mantrajs.com/say-hello-to-ES2015/introduction