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是一種新的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"; } }
能夠像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 經過使用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); }
接上篇
新增長的特性不影響老功能的使用,字符串將有新的文本格式,也增長了正則 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); } "
在語言層面上支持使用模塊來定義組件。將流行的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);
這四個對於常見的算法來講是頗有用的數據結構。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
代理建立的對象能夠得到宿主對象的所有行爲(屬性和方法)。能夠用於攔截,虛擬對象,日誌/分析等。
// 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:... }
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
加了一些新的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) }) //拷貝對象
增長了兩個新的數字進制標識符,第二個字母爲b來表示二進制,第二個字母爲o來表示八進制。
0b111110111 === 503 // true 二進制 0o767 === 503 // true 八進制
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)]); })
完整的反射API暴露了對象在運行時的元操做。這相似於一個反向代理,並容許調用與代理陷阱中相同的元操做。實現代理很是有用。
暫無實例
保證尾部調用時棧區不會沒有限制的增加,這使得遞歸函數及時在沒有限制的輸入時也能保證安全性。
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)