ES6,也叫ECMAScript2015(如下統稱ES6),是ECMAScript標準的最新版本。這個標準在2015年6月份被正式批准。ES6是js語言頗有意義的一次更新,也是2009年ES5被標準化以來第一次重大的更新。主流javascript引擎中的這些新特性正在開發中。
ES6特性完整版參見:ES6特性完整版說明
ES6有如下這些新特性:javascript
使用=>表示function的簡略版。這和C#,Java8,CoffeeScript的語法很像。它能夠支持聲明體和表達式體,而且表達式體會有一個返回值。不像普通函數,箭頭函數和其上下文共享同一個詞法做用域的this。
(譯者注:詞法做用域即「靜態做用域」,)html
1 // Expression bodies 表達式體 2 var odds = evens.map(v => v + 1); 3 /*v=>v+1至關於function(v){return v+1;}*/ 4 var nums = evens.map((v, i) => v + i); 5 var pairs = evens.map(v => ({even: v, odd: v + 1})); 6 7 // Statement bodies 聲明體 8 nums.forEach(v => { 9 if (v % 5 === 0) 10 fives.push(v); 11 }); 12 /*至關於nums.forEach(function (v) { 13 if (v % 5 === 0) fives.push(v); 14 });*/ 15 16 // Lexical this 詞法做用域的this 17 var bob = { 18 _name: "Bob", 19 _friends: [], 20 printFriends() { 21 this._friends.forEach(f => 22 console.log(this._name + " knows " + f)); 23 } 24 }
ES2015的classes是在基於原型的面向對象模式中的一個簡單的語法糖。它有一個簡單的聲明形式,使得類模式更易於使用,而且這種方式有益於互用性。classes支持基於原型的繼承、父類方法的調用、實例化和靜態方法、構造函數。
(譯者注:超級像後端語言。)java
1 class SkinnedMesh extends THREE.Mesh {//使用extends來表示繼承 2 constructor(geometry, materials) { 3 super(geometry, materials);//父類的構造函數 4 5 this.idMatrix = SkinnedMesh.defaultMatrix(); 6 this.bones = []; 7 this.boneMatrices = []; 8 //... 9 } 10 update(camera) { 11 //... 12 super.update(); 13 } 14 get boneCount() { 15 return this.bones.length; 16 } 17 set matrixType(matrixType) { 18 this.idMatrix = SkinnedMesh[matrixType](); 19 } 20 static defaultMatrix() {//靜態方法 21 return new THREE.Matrix4(); 22 } 23 }
對象字面量被擴展成能夠在構造階段設置原型、變量名和變量值相同時可使用簡寫形式(如foo:foo 能夠寫成foo)、定義方法、調用父方法、動態計算變量名。同時,這種方式也和上一小節說的類(class)聲明十分吻合,也使得基於對象的設計更加便利。python
1 var obj = { 2 // __proto__ obj的原型 3 __proto__: theProtoObj, 4 // Shorthand for ‘handler: handler’ 簡寫,翻譯過來就是handler : handler, 5 handler, 6 // Methods 7 toString() { 8 // Super calls 調用父類的函數 9 return "d " + super.toString(); 10 }, 11 // Computed (dynamic) property names 須要計算的動態屬性名稱 12 [ 'prop_' + (() => 42)() ]: 42 13 };
字符串模板提供了一個建立字符串的語法糖。這和perl、python等等語言中的字符串插入功能很相似。有選擇性的,它容許在字符串中插入一個標籤(tag)使得字符串的構建是可定製化的,這能夠避免在字符串裏進行注入攻擊,或者構造更高級別的結構。算法
1 // Basic literal string creation 基本的字符串字面量方式建立 2 `In JavaScript '\n' is a line-feed.` 3 4 // Multiline strings 多行字符串 5 `In JavaScript this is 6 not legal.` 7 8 // String interpolation 插入變量 9 var name = "Bob", time = "today"; 10 `Hello ${name}, how are you ${time}?` 11 12 // Construct an HTTP request prefix is used to interpret the replacements and construction 13 // 構建一個通用的http請求前綴,其中字段值能夠動態替換 14 POST`http://foo.org/bar?a=${a}&b=${b} 15 Content-Type: application/json 16 X-Credentials: ${credentials} 17 { "foo": ${foo}, 18 "bar": ${bar}}`(myOnReadyStateChangeHandler);
解構支持使用模式匹配來匹配數組和對象。結構是弱化失敗的,相似於在一個標準的對象中查找foo[「bar」]屬性,若是沒有找到只是返回undefined。
(譯者注:fail-soft-字面意思是弱化失敗,再這裏是指若是解析結構解析不出來不會拋異常,只是返回一個undefined或默認值)json
1 // list matching 匹配數組 2 var [a, , b] = [1,2,3]; 3 4 // object matching 匹配對象 5 var { op: a, lhs: { op: b }, rhs: c } 6 = getASTNode() 7 8 // object matching shorthand 匹配對象的一部分 9 // binds `op`, `lhs` and `rhs` in scope 例如getASTNode()的返回值爲{op,op2,lhs,rhs},這個表達式將會自動匹配op,lhs,rhs 10 /*稍微有點難懂,下面的語句翻譯過來就是 11 var _getASTNode = getASTNode(); 12 13 var op = _getASTNode.op; 14 var lhs = _getASTNode.lhs; 15 var rhs = _getASTNode.rhs; 16 */ 17 var {op, lhs, rhs} = getASTNode() 18 19 // Can be used in parameter position 能夠做爲參數使用 20 function g({name: x}) { 21 console.log(x); 22 } 23 g({name: 5}) 24 25 // Fail-soft destructuring 弱化解析失敗,返回undefined 26 var [a] = []; 27 a === undefined; 28 29 // Fail-soft destructuring with defaults 有默認值時弱化解析失敗,返回undefiend 30 var [a = 1] = []; 31 a === 1;
默認值:支持由被調用函數設置的參數默認值。
參數展開:在函數調用時實參使用...運算符,能夠將做爲參數的數組拆解爲連續的多個參數。 在函數定義時虛參使用...運算符,則能夠將函數尾部的多個參數綁定到一個數組中。
不定參數:不定參數取代了傳統的參數,並可更直接地應用於一般的用例中。後端
1 //默認值 2 function f(x, y=12) { 3 // y is 12 if not passed (or passed as undefined) 若是y沒有實參,則賦值爲默認值12 4 return x + y; 5 } 6 f(3) == 15
1 //不定個數的參數 2 function f(x, ...y) { 3 // y is an Array 有...,表示y是一個數組 4 return x * y.length; 5 } 6 f(3, "hello", true) == 6
1 //參數展開 2 function f(x, y, z) { 3 return x + y + z; 4 } 5 // Pass each elem of array as argument ...表示在數組中的每個元素分別按順序對應一個入參 6 f(...[1,2,3]) == 6
兩個關鍵字都具備塊級做用域,只在塊級做用域中生效。let是一種新的var。(譯者注:let能夠當作var,它定義的變量被限制在特定範圍中才能使用,離開這個範圍就自動銷燬)。const只能一次性聲明(譯者注:不能修改其值)。二者靜態限制防止了在賦值前使用變量。api
1 function f() { 2 { 3 let x; 4 { 5 // okay, block scoped name 不報錯 6 const x = "sneaky"; 7 // error, const 報錯,常量不容許修改值 8 x = "foo"; 9 } 10 // error, already declared in block 報錯,在該塊級做用域中已經聲明瞭 11 let x = "inner"; 12 } 13 }
能夠像CLR IEnumerable或JAVA Utterable同樣自定義迭代器。將for..in 變爲自定義且基於迭代器的for..of。不須要經過數組實現,能夠像LINQ同樣使用懶惰模式。數組
1 let fibonacci = { 2 [Symbol.iterator]() { 3 let pre = 0, cur = 1; 4 return { 5 next() { 6 [pre, cur] = [cur, pre + cur]; 7 return { done: false, value: cur } 8 } 9 } 10 } 11 } 12 13 for (var n of fibonacci) { 14 // truncate the sequence at 1000 實現從1到1000的斐波那契數列計算 15 if (n > 1000) 16 break; 17 console.log(n); 18 }
迭代器是基於這些鴨子類型的接口(使用TypeScript類型語法,僅僅用於闡述問題)promise
1 interface IteratorResult { 2 done: boolean; 3 value: any; 4 } 5 interface Iterator { 6 next(): IteratorResult; 7 } 8 interface Iterable { 9 [Symbol.iterator](): Iterator 10 }
Generators 經過使用function和yield簡化了迭代器編寫。函數聲明時若是是function 形式的會返回一個Generator實例。Generator是迭代器iterators的子類,還包括了額外的next和throw方法。這容許了值能夠迴流到生成器中,因此yield是返回一個值或者拋異常的一個表達式。
1 var fibonacci = { 2 [Symbol.iterator]: function*() { 3 var pre = 0, cur = 1; 4 for (;;) { 5 var temp = pre; 6 pre = cur; 7 cur += temp; 8 yield cur; 9 } 10 } 11 } 12 13 for (var n of fibonacci) { 14 // truncate the sequence at 1000 15 if (n > 1000) 16 break; 17 console.log(n); 18 }
生成器接口以下(此處使用TypeScript 的類型語法,僅用於闡述問題):
1 interface Generator extends Iterator { 2 next(value?: any): IteratorResult; 3 throw(exception: any); 4 }
新增長的特性不影響老功能的使用,字符串將有新的文本格式,也增長了正則 u 模式來處理碼位。同時,新的api能夠在21碼位級別上處理字符串。在javascript中,這些新增點能夠支持構建全球化應用。
1 // same as ES5.1 2 // 與 ES5.1 相同 3 "吉".length == 2 4 5 // new RegExp behaviour, opt-in ‘u’ 6 // 使用可選的‘u’修飾符表示正則 7 "吉".match(/./u)[0].length == 2 8 9 // new form 10 // 左邊是新寫法,右邊是舊寫法。新的形式能夠經過添加一組大括號`{}`來表示超過四字節的碼點 11 "\u{20BB7}"=="吉"=="\uD842\uDFB7" 12 13 // new String ops 14 "吉".codePointAt(0) == 0x20BB7 15 16 // for-of iterates code points 17 // 以碼位爲單位進行迭代 18 for(var c of "吉") { 19 console.log(c); 20 }
在語言層面上支持使用模塊來定義組件。將流行的javascript模塊加載器(AMD,CommonJS)的模式編成規範。運行時的行爲由宿主定義的默認加載器決定。隱式異步模型- (當前模塊)沒有代碼會執行,直到被請求的模塊可用且處理過。
1 // lib/math.js 2 export function sum(x, y) { //export 表示能夠被加載 3 return x + y; 4 } 5 export var pi = 3.141593;
1 // app.js 2 import * as math from "lib/math"; //import 表示被導入 3 alert("2π = " + math.sum(math.pi, math.pi));
1 // otherApp.js 2 import {sum, pi} from "lib/math"; 3 console.log("2π = " + sum(pi, pi));
額外的新增的特徵包括export default和export * ;
1 // lib/mathplusplus.js 2 export * from "lib/math"; 3 export var e = 2.71828182846; 4 export default function(x) {//注意default關鍵字表示默認 5 return Math.log(x); 6 }
1 // app.js 2 import exp, {pi, e} from "lib/mathplusplus"; 3 console.log("e^π = " + exp(pi));
這四個對於常見的算法來講是頗有用的數據結構。weakMaps這一數據結構提供的索引表,擁有不會發生內存泄露的對象鍵名。(注:指的是當對象做爲鍵名時,對象可能會被回收,回收後自動移除所在鍵值對)。
1 // Sets 2 var s = new Set(); 3 s.add("hello").add("goodbye").add("hello"); 4 s.size === 2; 5 s.has("hello") === true; 6 7 // Maps 8 var m = new Map(); 9 m.set("hello", 42); 10 m.set(s, 34); 11 m.get(s) == 34; 12 13 // Weak Maps 14 var wm = new WeakMap(); 15 wm.set(s, { extra: 42 }); 16 wm.size === undefined 17 18 // Weak Sets 19 var ws = new WeakSet(); 20 ws.add({ data: 42 }); 21 // Because the added object has no other references, it will not be held in the set 22 //由於這個新的對象沒有其餘引用,因此不會真的添加到set
代理建立的對象能夠得到宿主對象的所有行爲(屬性和方法)。能夠用於攔截,虛擬對象,日誌/分析等。
1 // Proxying a normal object 代理一個普通對象 2 var target = {};//被代理的類 3 var handler = {//第二個參數表示攔截後的操做 4 get: function (receiver, name) {//這裏是攔截獲取屬性的操做:p.world 至關於第二個參數name爲world 5 return `Hello, ${name}!`; 6 } 7 }; 8 9 var p = new Proxy(target, handler); 10 p.world === 'Hello, world!';
1 // Proxying a function object 代理一個函數對象 2 var target = function () { return 'I am the target'; }; 3 var handler = { 4 apply: function (receiver, ...args) { 5 return 'I am the proxy'; 6 } 7 }; 8 9 var p = new Proxy(target, handler); 10 p() === 'I am the proxy';
這裏是全部運行時級別的元數據操做陷阱:
1 var handler = 2 { 3 get:..., 4 set:..., 5 has:..., 6 deleteProperty:..., 7 apply:..., 8 construct:..., 9 getOwnPropertyDescriptor:..., 10 defineProperty:..., 11 getPrototypeOf:..., 12 setPrototypeOf:..., 13 enumerate:..., 14 ownKeys:..., 15 preventExtensions:..., 16 isExtensible:... 17 }
symbol有權限控制對象狀態。symbol容許經過String(與ES5相同)或symbol做爲鍵來訪問對象的屬性。symbol是一個新的原始類型。可選的name參數用於調試-可是它不是符號身份的一部分。符號是惟一的(就像gensym),可是隻要他們經過像Object.getOwnPropertySymbles這樣的反射特性暴露出來,就不是私有的。
1 var MyClass = (function() { 2 3 // module scoped symbol 4 var key = Symbol("key"); 5 6 function MyClass(privateData) { 7 this[key] = privateData; 8 } 9 10 MyClass.prototype = { 11 doStuff: function() { 12 ... this[key] ... 13 } 14 }; 15 16 return MyClass; 17 })(); 18 19 var c = new MyClass("hello") 20 c["key"] === undefined//已經跳出了做用域,因此是undefined
在ES6中,像Array,Date和Dom元素這樣的內建對象均可以被子類化。
1 // User code of Array subclass 2 class MyArray extends Array { 3 constructor(...args) { super(...args); } 4 } 5 6 var arr = new MyArray(); 7 arr[1] = 12; 8 arr.length == 2
加了一些新的api,包括math的核心庫,數組轉換幫助函數,和用來複制對象的Object.assign。
1 Number.EPSILON 2 Number.isInteger(Infinity) // false 是不是整形 3 Number.isNaN("NaN") // false 是不是非法數字 4 5 Math.acosh(3) // 1.762747174039086 餘弦 6 Math.hypot(3, 4) // 5 直角三角形的斜邊 7 Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2 帶符號的懲罰 8 9 "abcde".includes("cd") // true 10 "abc".repeat(3) // "abcabcabc" 11 12 Array.from(document.querySelectorAll('*')) // Returns a real Array 13 Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior 14 [0, 0, 0].fill(7, 1) // [0,7,7] 15 [1, 2, 3].find(x => x == 3) // 3 16 [1, 2, 3].findIndex(x => x == 2) // 1 17 [1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2] 18 ["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"] 19 ["a", "b", "c"].keys() // iterator 0, 1, 2 20 ["a", "b", "c"].values() // iterator "a", "b", "c" 21 22 Object.assign(Point, { origin: new Point(0,0) }) //拷貝對象
增長了兩個新的數字進制標識符,第二個字母爲b來表示二進制,第二個字母爲o來表示八進制。
1 0b111110111 === 503 // true 二進制 2 0o767 === 503 // true 八進制
Promises是處理異步操做的一種模式。 Promises是第一個能表明將來能用到的值的類。Promises已經被使用在不少JavaScript第三庫中。
1 function timeout(duration = 0) { 2 return new Promise((resolve, reject) => { 3 setTimeout(resolve, duration); 4 }) 5 } 6 7 var p = timeout(1000).then(() => { 8 return timeout(2000); 9 }).then(() => { 10 throw new Error("hmm"); 11 }).catch(err => { 12 return Promise.all([timeout(100), timeout(200)]); 13 })
完整的反射API暴露了對象在運行時的元操做。這相似於一個反向代理,並容許調用與代理陷阱中相同的元操做。實現代理很是有用。
1 var O = {a: 1}; 2 Object.defineProperty(O, 'b', {value: 2}); 3 O[Symbol('c')] = 3; 4 5 Reflect.ownKeys(O); // ['a', 'b', Symbol(c)] 6 7 function C(a, b){ 8 this.c = a + b; 9 } 10 var instance = Reflect.construct(C, [20, 22]); 11 instance.c; // 42
保證尾部調用時棧區不會沒有限制的增加,這使得遞歸函數及時在沒有限制的輸入時也能保證安全性。
1 function factorial(n, acc = 1) { 2 'use strict'; 3 if (n <= 1) return acc; 4 return factorial(n - 1, n * acc); 5 } 6 // Stack overflow in most implementations today, 棧溢出在如今常常存在 7 // but safe on arbitrary inputs in ES6 可是在ES6中卻很安全 8 factorial(100000)