ES6的特性(譯+註解)

介紹  

  ES6,也叫ECMAScript2015(如下統稱ES6),是ECMAScript標準的最新版本。這個標準在2015年6月份被正式批准。ES6是js語言頗有意義的一次更新,也是2009年ES5被標準化以來第一次重大的更新。主流javascript引擎中的這些新特性正在開發中。
  ES6特性完整版參見:ES6特性完整版說明
  ES6有如下這些新特性:javascript

箭頭函數

  使用=>表示function的簡略版。這和C#,Java8,CoffeeScript的語法很像。它能夠支持聲明體和表達式體,而且表達式體會有一個返回值。不像普通函數,箭頭函數和其上下文共享同一個詞法做用域的this。
 (譯者注:詞法做用域即「靜態做用域」,)html

// Expression bodies 表達式體
var odds = evens.map(v => v + 1);
/*v=>v+1至關於function(v){return v+1;}*/
var nums = evens.map((v, i) => v + i);
var pairs = evens.map(v => ({even: v, odd: v + 1}));

// Statement bodies 聲明體
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});
/*至關於nums.forEach(function (v) {
  if (v % 5 === 0) fives.push(v);
});*/

// Lexical this  詞法做用域的this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
}

  ES2015的classes是在基於原型的面向對象模式中的一個簡單的語法糖。它有一個簡單的聲明形式,使得類模式更易於使用,而且這種方式有益於互用性。classes支持基於原型的繼承、父類方法的調用、實例化和靜態方法、構造函數。
  (譯者注:超級像後端語言。)java

class SkinnedMesh extends THREE.Mesh {//使用extends來表示繼承
  constructor(geometry, materials) {
    super(geometry, materials);//父類的構造函數

    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  update(camera) {
    //...
    super.update();
  }
  get boneCount() {
    return this.bones.length;
  }
  set matrixType(matrixType) {
    this.idMatrix = SkinnedMesh[matrixType]();
  }
  static defaultMatrix() {//靜態方法
    return new THREE.Matrix4();
  }
}

加強的對象字面量

  對象字面量被擴展成能夠在構造階段設置原型、變量名和變量值相同時可使用簡寫形式(如foo:foo 能夠寫成foo)、定義方法、調用父方法、動態計算變量名。同時,這種方式也和上一小節說的類(class)聲明十分吻合,也使得基於對象的設計更加便利。python

var obj = {
    // __proto__  obj的原型
    __proto__: theProtoObj,
    // Shorthand for ‘handler: handler’    簡寫,翻譯過來就是handler : handler,
    handler,
    // Methods
    toString() {
     // Super calls  調用父類的函數
     return "d " + super.toString(); 
    },
    // Computed (dynamic) property names 須要計算的動態屬性名稱
    [ 'prop_' + (() => 42)() ]: 42
};

字符串模板

  字符串模板提供了一個建立字符串的語法糖。這和perl、python等等語言中的字符串插入功能很相似。有選擇性的,它容許在字符串中插入一個標籤(tag)使得字符串的構建是可定製化的,這能夠避免在字符串裏進行注入攻擊,或者構造更高級別的結構。git

// Basic literal string creation  基本的字符串字面量方式建立
`In JavaScript '\n' is a line-feed.`

// Multiline strings   多行字符串
`In JavaScript this is
 not legal.`

// String interpolation 插入變量
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Construct an HTTP request prefix is used to interpret the replacements and construction
// 構建一個通用的http請求前綴,其中字段值能夠動態替換
POST`http://foo.org/bar?a=${a}&b=${b}
     Content-Type: application/json
     X-Credentials: ${credentials}
     { "foo": ${foo},
       "bar": ${bar}}`(myOnReadyStateChangeHandler);

解構(解析結構)

  解構支持使用模式匹配來匹配數組和對象。結構是弱化失敗的,相似於在一個標準的對象中查找foo[「bar」]屬性,若是沒有找到只是返回undefined。
  (譯者注:fail-soft-字面意思是弱化失敗,再這裏是指若是解析結構解析不出來不會拋異常,只是返回一個undefined或默認值)es6

// list matching 匹配數組
var [a, , b] = [1,2,3];

// object matching 匹配對象
var { op: a, lhs: { op: b }, rhs: c }
       = getASTNode()

// object matching shorthand  匹配對象的一部分
// binds `op`, `lhs` and `rhs` in scope 例如getASTNode()的返回值爲{op,op2,lhs,rhs},這個表達式將會自動匹配op,lhs,rhs
/*稍微有點難懂,下面的語句翻譯過來就是
var _getASTNode = getASTNode();

var op = _getASTNode.op;
var lhs = _getASTNode.lhs;
var rhs = _getASTNode.rhs;
*/
var {op, lhs, rhs} = getASTNode()

// Can be used in parameter position 能夠做爲參數使用
function g({name: x}) {
  console.log(x);
}
g({name: 5})

// Fail-soft destructuring 弱化解析失敗,返回undefined
var [a] = [];
a === undefined;

// Fail-soft destructuring with defaults  有默認值時弱化解析失敗,返回undefiend
var [a = 1] = [];
a === 1;

默認值+不定參數+參數展開

  默認值:支持由被調用函數設置的參數默認值。
  參數展開:在函數調用時實參使用...運算符,能夠將做爲參數的數組拆解爲連續的多個參數。 在函數定義時虛參使用...運算符,則能夠將函數尾部的多個參數綁定到一個數組中。
  不定參數:不定參數取代了傳統的參數,並可更直接地應用於一般的用例中。算法

//默認值
function f(x, y=12) {
  // y is 12 if not passed (or passed as undefined) 若是y沒有實參,則賦值爲默認值12
  return x + y;
}
f(3) == 15
//不定個數的參數
function f(x, ...y) {
  // y is an Array    有...,表示y是一個數組
  return x * y.length;
}
f(3, "hello", true) == 6
//參數展開
function f(x, y, z) {
  return x + y + z;
}
// Pass each elem of array as argument ...表示在數組中的每個元素分別按順序對應一個入參
f(...[1,2,3]) == 6

let和const關鍵字

  兩個關鍵字都具備塊級做用域,只在塊級做用域中生效。let是一種新的var。(譯者注:let能夠當作var,它定義的變量被限制在特定範圍中才能使用,離開這個範圍就自動銷燬)。const只能一次性聲明(譯者注:不能修改其值)。二者靜態限制防止了在賦值前使用變量。編程

function f() {
  {
    let x;
    {
      // okay, block scoped name  不報錯
      const x = "sneaky";
      // error, const 報錯,常量不容許修改值
      x = "foo";
    }
    // error, already declared in block 報錯,在該塊級做用域中已經聲明瞭
    let x = "inner";
  }
}

Iterator+For..Of 迭代器

  能夠像CLR IEnumerable或JAVA Utterable同樣自定義迭代器。將for..in 變爲自定義且基於迭代器的for..of。不須要經過數組實現,能夠像LINQ同樣使用懶惰模式。json

let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        return { done: false, value: cur }
      }
    }
  }
}

for (var n of fibonacci) {
  // truncate the sequence at 1000 實現從1到1000的斐波那契數列計算
  if (n > 1000)
    break;
  console.log(n);
}

  迭代器是基於這些鴨子類型的接口(使用TypeScript類型語法,僅僅用於闡述問題)
  (譯者注:duck typing 鴨子類型。源自於James Whitcomb Riley提出的鴨子測試——「當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就能夠被稱爲鴨子。」再使用鴨子類型的語言中,若某函數定義是按照入參爲鴨子類型的參數來編寫的,那麼運行時接受的參數無論不是鴨子類型的,都會調用它游泳、叫得方法,若是調不到就會報錯。關注的不是對象的類型自己,而是它是如何使用的。js就支持鴨子類型。動態語言都醬紫。)後端

interface IteratorResult {
  done: boolean;
  value: any;
}
interface Iterator {
  next(): IteratorResult;
}
interface Iterable {
  [Symbol.iterator](): Iterator
}

Generators 生成器

  Generators 經過使用function和yield簡化了迭代器編寫。函數聲明時若是是function 形式的會返回一個Generator實例。Generator是迭代器iterators的子類,還包括了額外的next和throw方法。這容許了值能夠迴流到生成器中,因此yield是返回一個值或者拋異常的一個表達式。
注意:也能夠用做await 同樣的異步編程中

var fibonacci = {
  [Symbol.iterator]: function*() {
    var pre = 0, cur = 1;
    for (;;) {
      var temp = pre;
      pre = cur;
      cur += temp;
      yield cur;
    }
  }
}

for (var n of fibonacci) {
  // truncate the sequence at 1000
  if (n > 1000)
    break;
  console.log(n);
}

  生成器接口以下(此處使用TypeScript 的類型語法,僅用於闡述問題):
  

interface Generator extends Iterator {
    next(value?: any): IteratorResult;
    throw(exception: any);
}

接上篇

Unicode

  新增長的特性不影響老功能的使用,字符串將有新的文本格式,也增長了正則 u 模式來處理碼位。同時,新的api能夠在21碼位級別上處理字符串。在javascript中,這些新增點能夠支持構建全球化應用。

// same as ES5.1
// 與 ES5.1 相同
"吉".length == 2

// new RegExp behaviour, opt-in ‘u’
// 使用可選的‘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);
}
"

模塊 modules

  在語言層面上支持使用模塊來定義組件。將流行的javascript模塊加載器(AMD,CommonJS)的模式編成規範。運行時的行爲由宿主定義的默認加載器決定。隱式異步模型- (當前模塊)沒有代碼會執行,直到被請求的模塊可用且處理過。

// lib/math.js
export function sum(x, y) {  //export 表示能夠被加載
  return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math"; //import 表示被導入
alert("2π = " + math.sum(math.pi, math.pi));
// app.js
import * as math from "lib/math"; 
alert("2π = " + math.sum(math.pi, math.pi));

  額外的新增的特徵包括export default和export * ;

// lib/mathplusplus.js
export * from "lib/math"; 
export var e = 2.71828182846;
export default function(x) {//注意default關鍵字表示默認
    return Math.log(x);
}
// app.js
import ln, {pi, e} from "lib/mathplusplus";
alert("2π = " + ln(e)*pi*2);

Map + Set + WeakMap + WeakSet

  這四個對於常見的算法來講是頗有用的數據結構。weakMaps這一數據結構提供的索引表,擁有不會發生內存泄露的對象鍵名。(注:指的是當對象做爲鍵名時,對象可能會被回收,回收後自動移除所在鍵值對)。

// 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
//由於這個新的對象沒有其餘引用,因此不會真的添加到set

Proxies 代理

  代理建立的對象能夠得到宿主對象的所有行爲(屬性和方法)。能夠用於攔截,虛擬對象,日誌/分析等。

// Proxying a normal object 代理一個普通對象
var target = {};//被代理的類
var handler = {//第二個參數表示攔截後的操做
  get: function (receiver, name) {//這裏是攔截獲取屬性的操做:p.world 至關於第二個參數name爲world
    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';

  這裏是全部運行時級別的元數據操做陷阱:

var handler =
{
  get:...,
  set:...,
  has:...,
  deleteProperty:...,
  apply:...,
  construct:...,
  getOwnPropertyDescriptor:...,
  defineProperty:...,
  getPrototypeOf:...,
  setPrototypeOf:...,
  enumerate:...,
  ownKeys:...,
  preventExtensions:...,
  isExtensible:...
}

Symbols 符號

  symbol有權限控制對象狀態。symbol容許經過String(與ES5相同)或symbol做爲鍵來訪問對象的屬性。symbol是一個新的原始類型。可選的name參數用於調試-可是它不是符號身份的一部分。符號是惟一的(就像gensym),可是隻要他們經過像Object.getOwnPropertySymbles這樣的反射特性暴露出來,就不是私有的。

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//已經跳出了做用域,因此是undefined

內建對象可擁有子類

在ES6中,像Array,Date和Dom元素這樣的內建對象均可以被子類化。

// Pseudo-code of Array
class Array {
    constructor(...args) { /* ... */ }
    static [Symbol.create]() {
        // Install special [[DefineOwnProperty]]
        // to magically update 'length'
    }
}

// User code of Array subclass
class MyArray extends Array {
    constructor(...args) { super(...args); }
}

// Two-phase 'new':
// 1) Call @@create to allocate object
// 2) Invoke constructor on new instance
/*
兩個階段的new:
1) 調用@@create來爲對象分配空間
2)在新實例上調用構造函數
*/
var arr = new MyArray();
arr[1] = 12;
arr.length == 2

  

Math + Number + String + Object APIs

  加了一些新的api,包括math的核心庫,數組轉換幫助函數,和用來複制對象的Object.assign。 

Number.EPSILON
Number.isInteger(Infinity) // false 是不是整形
Number.isNaN("NaN") // false 是不是非法數字

Math.acosh(3) // 1.762747174039086 餘弦
Math.hypot(3, 4) // 5  直角三角形的斜邊
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2   帶符號的懲罰

"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"

Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) }) //拷貝對象

Binary and Octal Literals

  增長了兩個新的數字進制標識符,第二個字母爲b來表示二進制,第二個字母爲o來表示八進制。

0b111110111 === 503 // true 二進制
0o767 === 503 // true 八進制

Promises

  Promises是處理異步操做的一種模式。 Promises是第一個能表明將來能用到的值的類。Promises已經被使用在不少JavaScript第三庫中。

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)]);
})

Reflect API

  完整的反射API暴露了對象在運行時的元操做。這相似於一個反向代理,並容許調用與代理陷阱中相同的元操做。實現代理很是有用。

暫無實例

Tail Calls

  保證尾部調用時棧區不會沒有限制的增加,這使得遞歸函數及時在沒有限制的輸入時也能保證安全性。

function factorial(n, acc = 1) {
    'use strict';
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}
// Stack overflow in most implementations today, 棧溢出在如今常常存在
// but safe on arbitrary inputs in ES6  可是在ES6中卻很安全
factorial(100000)

附錄

常見英文詞彙

  • pattern 模式
  • literal 字面量
  • lexical 詞法做用域
  • surrounding code 上下文
  • Object literals 對象字面量
  • Rest 不定參數
  • assignment 賦值
相關文章
相關標籤/搜索