ECMAScript6 是最新的ECMAScript標準,於2015年6月正式推出(因此也稱爲ECMAScript 2015),相比於2009年推出的es5, es6定義了更加豐富的語言特性,基於該標準的Javascript語言也迎來了語法上的重大變革。本文列舉了部分es6新特性,但願以前沒接觸es6的小夥伴讀完本文能對下一代js編程有一個初步的認識。javascript
箭頭函數用 "=>"簡化函數定義,相似於C#, Java8中的Lambda表達式,支持語句塊和表達式函數體,和普通函數的惟一區別在於函數體引用的 this 和包裹代碼的this一致。java
// 表達式 var odds = evens.map(v => v + 1); var nums = evens.map((v, i) => v + i); var pairs = evens.map(v => ({even: v, odd: v + 1})); // 代碼塊 nums.forEach(v => { if (v % 5 === 0) fives.push(v); }); // this , 這裏 this引用 leon var bob = { _name: "leon", _friends: [], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } }
ES6的類簡單而言只是基於原型繼承的語法糖, 使用方便的聲明式定義,使得類型定義和其餘面嚮對象語言一致。類支持原型繼承,父類調用,實體和靜態方法以及構造函數。node
'use strict' class Animal { constructor(name) { this.name = name; } speak(msg) { console.log(`${this.name} says ${msg}`); } static fight(a, b) { console.log(`${a.name} and ${b.name} are fighting!`); } } class Dog extends Animal { constructor(name) { super('DOG' + name); } } let dogA = new Dog('foo'); let dogB = new Dog('bar'); dogA.speak('hi'); dogB.speak(`what's up`) Animal.fight(dogA, dogB); /** *DOGfoo says hi *DOGbar says what's up *DOGfoo and DOGbar are fighting! */
對象字面量如今支持在對象構建時設置原型對象,定義方法,調用父類構造函數,以及用表達式計算屬性. 這些特性使得對象字面量定義和類型定義十分類似, 給基於對象的設計帶來了便利。git
var obj = { // 原型對象 __proto__: theProtoObj, // 簡化定義成員, ‘handler: handler’ handler, // 方法 toString() { // 父類調用 return "d " + super.toString(); }, // 動態屬性名 [ 'prop_' + (() => 42)() ]: 42 };
模板字符串提供了一種構建字符串的語法糖,相似於Perl, Python和其餘語言中的字符串插值特性.程序員
// 多行字符串 `In JavaScript this is not legal.` // 字符串插值 var name = "Leon", time = "today"; `Hello ${name}, how are you ${time}?`
解構賦值容許你使用相似數組或對象字面量的語法將數組和對象的屬性賦給各類變量。這種賦值語法極度簡潔,同時還比傳統的屬性訪問方法更爲清晰。es6
// 數組 a=1,b=2,c=3 var [a, b, c] = [1,2,3]; // 數組,沒有匹配的返回undefined , a=1,b=2,c=undefined var [a, b, c] = [1,2]; // 對象, m='leon', n=18 var {name:m,age:n}={name:'leon',age:18} // 對象屬性名與變量名一致時,能夠簡寫爲 var {foo,bar}={foo:'1',bar:2} // 嵌套 name='leon' var {x:{y:{z:name}}}={x:{y:{z:'leon'}}}
函數調用者不須要傳遞全部可能存在的參數,沒有被傳遞的參數由默認參數進行填充。 在全部函數參數中,只有最後一個才能夠被標記爲不定參數。函數被調用時,不定參數前的全部參數都正常填充,任何「額外的」參數都被放進一個數組中並賦值給不定參數。若是沒有額外的參數,不定參數就是一個空數組,它永遠不會是undefined。github
// 默認參數 function f(x, y=12) { // 若是沒有傳入y 或傳入的值爲undefined ,則y=12 return x + y; } f(3) == 15 // 不定參數 function f(x, ...y) { // y 是一個數組 return x * y.length; } f(3, "hello", true) == 6 function f(x, y, z) { return x + y + z; } // 數組中的每一個元素做爲參數傳入 f(...[1,2,3]) == 6
let 和 const 聲明的變量具備塊級做用域, 傳統使用var申明的變量在整個函數內均可訪問。const聲明的變量只能夠在聲明時賦值,不可隨意修改,不然會致使SyntaxError(語法錯誤)。web
function f() { { let x; { const x = "me"; // 由於是const, 因此不可修改,報錯 x = "foo"; } // 報錯, 用let重定義變量會拋出一個語法錯誤 let x = "inner"; } }
迭代器相似於 .NET CLR 的 IEnumerable 或 Java 的 Iterable, 全部擁有[Symbol.iterator]的對象被稱爲可迭代的, 而 for ..of 用於遍歷實現了迭代器方法的對象,好比Array, Map, Set, Array-like Object編程
for (var value of [1,2,3]) { // 依次打印 1,2,3 console.log(value); }
生成器對象由生成器函數(function* 定義的函數)返回,它同時準守iterator 和 Iterable 協議。著名的koa nodejs框架就是基於此特性構建。數組
'use strict' function* gen(i){ yield i+1; yield i+2; } function* gen1(i){ yield i; yield* gen(i); // delegate to gen, after gen finished , delegate back and continue yield i+3; return 'finished'; } let g=gen1(10); // g is a generator object console.log(g.next().value); // 10 console.log(g.next().value); // 11 console.log(g.next().value); // 12 console.log(g.next().value); // 13 console.log(g.next().value); // finished console.log(g.next().value); // undefined
模塊已經獲得語言級別的支持,ES6的模塊設計參照了AMD CommonJS 規範。
// lib/math.js // export 定義要導出的對象 export function sum(x, y) { return x + y; } export var pi = 3.141593; // 沒加export, 因此foo不被導出 function foo(){} // app.js // 導入所有在lib/math.js中標記爲導出的對象 import * as math from "lib/math"; alert("2π = " + math.sum(math.pi, math.pi)); // otherApp.js // 顯示標記須要導入的成員 import {sum, pi} from "lib/math"; alert("2π = " + sum(pi, pi)); // lib/mathplusplus.js // 導入lib/math中的所有對象並從新導出 export * from "lib/math"; export var e = 2.71828182846; // 默認導出對象 export default function(x) { return Math.log(x); } // app.js // ln爲上面的默認導出對象, pi來自於lib/math,e來自於mathplusplus import ln, {pi, e} from "lib/mathplusplus"; alert("2π = " + ln(e)*pi*2);
// 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 });
Symbol是es6新添加的一個基元數據類型, 其餘的基元類型有string,number,boolean,null,undefined. Symbol是惟一的,通常用做對象的key以存取相關狀態信息。
'use strict' //A symbol is a unique and immutable data type and may be used as an identifier for object properties. //Symbol([description]) let s1 = Symbol(); let s2 = Symbol('hi'); let s3 = Symbol('how are you'); let obj = {[s1]: 18}; // need [] to wrap obj[s2] = "hello"; console.log(obj[s1]); //18 console.log(obj[s2]); //hello obj[s3] = `I'm fine,thank you`; for (let s of Object.getOwnPropertySymbols(obj)) { /** Symbol() Symbol(hi) Symbol(how are you) * */ console.log(s); } var ar = Object.getOwnPropertySymbols(obj); console.log(ar.length); // 3
ES6中的內置對象,好比 Array, Date 等能夠被子類繼承
// 這裏定義一個Array的子類MyArray class MyArray extends Array { constructor(...args) { super(...args); } }
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('*')) // 返回一個真實的數組 [1, 2, 3].find(x => x == 3) // 3 [1, 2, 3].findIndex(x => x == 2) // 1 ["a", "b", "c"].keys() // iterator 0, 1, 2 ["a", "b", "c"].values() // iterator "a", "b", "c" Object.assign(Point, { origin: new Point(0,0) })
// 二進制 0b111110111 === 503 // true // 八進制 0o767 === 503 // true
Promise 是異步編程的一種規範,解決了js異步編程中callback hell問題, 在es6中原生支持.
'use strict' let p=new Promise(function(resolve,reject){ setTimeout(function(){ resolve(1); },100); }); p.then(function(v){ console.log(`the previous function returned ${v}`); }); Promise.resolve(1).then(function(v){ console.log(v); //1 }).catch(function(r){ console.log(r); }); Promise.reject('failed-leon').then(function(v){ console.log(v); }).catch(function(r){ console.log(r); // failed-leon }); Promise.reject('failed').then(function(v){ console.log(v); },function(r){ console.log(r+'0'); // failed0 }).catch(function(r){ console.log(r+'1'); // not executed }); //Returns a promise that either resolves when all of the promises in the iterable argument have resolved or rejects as soon as one of the promises in the iterable argument rejects. If the returned promise resolves, it is resolved with an array of the values from the resolved promises in the iterable. If the returned promise rejects, it is rejected with the reason from the promise in the iterable that rejected. This method can be useful for aggregating results of multiple promises together. Promise.all([Promise.resolve(1),Promise.resolve(2),Promise.resolve(3)]).then(function(vs){ for(let v of vs){ console.log(v); // 1 2 3 } }); //Returns a promise that resolves or rejects as soon as one of the promises in the iterable resolves or rejects, with the value or reason from that promise. Promise.race([Promise.resolve('a'),Promise.resolve('b'),Promise.resolve('c')]).then(function(v){ console.log(v); // a });
除了以上特性,es6還加強了對unicode編碼的支持,以便更好的支持應用國際化, 還有代理等等特性,這裏就不一一列舉了,目前javascript開發範圍越來普遍,web, 移動應用,智能家居...2015年中旬es6規範正式推出,儘管當前各廠商瀏覽器js引擎對es6尚未徹底支持,可是新版的nodejs已經默認支持了大部分es6特性,並且咱們還能夠利用babel將es6編譯成es5供瀏覽器端使用。另外對於.net/java程序員而言,新增的es6特性無需費多大力氣就能夠熟悉,因此尚未開始接觸es6的小夥伴如今能夠投入es6的懷抱,用js去改變世界了!