這裏有三種簡單地方式用於ES6編程:html
Web瀏覽器:使用Babel REPL,能夠將ES6編譯成ES5的平臺,而且並不須要安裝。node
命令行:使用babel-node
,能夠執行ES6的Node.js版本(會在內部編譯es5)。須要經過npm
安裝。git
各類js引擎:根據ES6語法兼容表,找出被支持的ES6功能。es6
對於第一點和第二點,這有更多細節。github
Babel REPL主要有四個部分:npm
一、左上角包含es6源代碼
二、左下角能夠查看es6中的語法錯誤
三、右上角是es6被編譯成es5的源代碼
四、右下角是經過console.log()
的輸出結果編程
babel-node能夠經過npm
安裝:數組
$ npm install --global babel
跟node同樣,能夠命令開啓REPL交互:瀏覽器
$ babel-node
一旦開啓REPL,就能夠去執行ES6代碼:babel
> let arr = [1, 2, 3]; > arr.map(x => x * x) [ 1, 4, 9 ]
注意:babel-node目前不支持多行輸入
Babel官網上有管多關於Babel CLI的工具。
es6有兩種新的方式來聲明變量:
一、let
用於聲明塊級做用於變量
二、const
用於聲明常量,其值不能被改變。
let
或const
能夠用來替代var
聲明變量,可是不能盲目使用,由於不一樣的做用域會改變代碼的行爲。例如:
var x = 3; function func(randomize) { if (randomize) { var x = Math.random(); // (A) scope: whole function return x; } return x; // accesses the x from line A } func(false); // undefined
func()
會意外地返回undefined
。你能夠重寫這部分代碼,就知道爲何返回undefined
了:
var x = 3; function func(randomize) { var x; if (randomize) { x = Math.random(); return x; } return x; } func(false); // undefined
若是用let
代替以前的var
,就會獲得不一樣的結果:
let x = 3; function func(randomize) { if (randomize) { let x = Math.random(); return x; } return x; } func(false); // 3
所以,盲目地用let
或const
代替var
是有風險的,個人建議是:
一、只在新代碼中使用let
或const
二、丟棄舊代碼或仔細認證
更多信息:es6中的變量和做用域
在es5中,若是要維護本地變量,不得不使用IIFE:
(function () { // open IIFE var tmp = ···; ··· }()); // close IIFE console.log(tmp); // ReferenceError
而在es6中,則只須要代碼塊和let
聲明:
{ // open block let tmp = ···; ··· } // close block console.log(tmp); // ReferenceError
更多信息:避免IIFEs
在es6中,對於字符串插值和多行字符串,Javscript能獲得其字面值。
在es5中,是將結果放在字符串中進行拼接:
function printCoord(x, y) { console.log('('+x+', '+y+')'); }
es6中,經過字符串字面模板,能夠在字符串中插入變量值:
function printCoord(x, y) { console.log(`(${x}, ${y})`); }
模板字面量也能輸出多行字符串。
例如,在es5中,輸出多行字符串,得這樣:
var HTML5_SKELETON = '<!doctype html>\n' + '<html>\n' + '<head>\n' + ' <meta charset="UTF-8">\n' + ' <title></title>\n' + '</head>\n' + '<body>\n' + '</body>\n' + '</html>\n';
若是經過反斜線轉義新行,代碼看起來會舒服點(但仍是要顯示的添加新行):
var HTML5_SKELETON = '\ <!doctype html>\n\ <html>\n\ <head>\n\ <meta charset="UTF-8">\n\ <title></title>\n\ </head>\n\ <body>\n\ </body>\n\ </html>';
而es6得模板字面量能跨多行:
const HTML5_SKELETON = ` <!doctype html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> </body> </html>`;
更多信息:字面量模板
在es5中,在函數表達式中必須當心使用this
。在示例中,我建立了輔助變量_this_
,以便於我能再line B處使用:
function UiComponent { var _this = this; // (A) var button = document.getElementById('myButton'); button.addEventListener('click', function () { console.log('CLICK'); _this.handleClick(); // (B) }); } UiComponent.prototype.handleClick = function () { ··· };
在es6中,可使用箭頭函數,它不會影響this
:
class UiComponent { constructor() { let button = document.getElementById('myButton'); button.addEventListener('click', () => { console.log('CLICK'); this.handleClick(); // (A) }); } handleClick() { ··· } }
對於只返回結果的短小回調函數,箭頭函數是很是便利的。
在es5中,以下的回調是相對冗長的:
var arr = [1, 2, 3]; var squares = arr.map(function (x) { return x * x });
在es6中,箭頭函數會更簡潔:
let arr = [1, 2, 3]; let squares = arr.map(x => x * x);
在定義參數時,若是隻有一個參數,括號是能夠省略的。於是,(x) => x x and x => x x 都是容許的。
更多信息:箭頭函數
一些函數或方法能經過數組或對象返回多個值。在es5中,老是須要建立中間變量來訪問返回值。es6中,可使用解構。
exec()
返回類數組對象的捕獲組。es5中,當要訪問捕獲組的值時,須要一箇中間變量:
var matchObj = /^(\d\d\d\d)-(\d\d)-(\d\d)$/ .exec('2999-12-31'); var year = matchObj[1]; var month = matchObj[2]; var day = matchObj[3];
es6中,解構使代碼更簡單:
let [, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/ .exec('2999-12-31');
空得逗號表示跳過數組的第一個元素。
Object.getOwnPropertyDescriptor()
會返回一個屬性描述符對象。
es5中,仍須要一箇中間變量來訪問你感興趣的對象屬性值:
var obj = { foo: 123 }; var propDesc = Object.getOwnPropertyDescriptor(obj, 'foo'); var writable = propDesc.writable; var configurable = propDesc.configurable; console.log(writable, configurable); // true true
es6,可使用解構:
let obj = { foo: 123 }; let {writable, configurable} = Object.getOwnPropertyDescriptor(obj, 'foo'); console.log(writable, configurable); // true true
{writable, configurable}
的值以下:
{ writable: writable, configurable: configurable }
更多信息:解構
先說es6,通常會這樣迭代數組:
var arr = ['a', 'b', 'c']; for (var i=0; i<arr.length; i++) { var elem = arr[i]; console.log(elem); }
也可使用Array
的forEach
:
arr.forEach(function (elem) { console.log(elem); });
for
循環的優勢是能夠中斷,forEach
的優勢是簡潔。
而es6的for-of
循環則結合了二者的優勢:
let arr = ['a', 'b', 'c']; for (let elem of arr) { console.log(elem); }
for-of
循環也能經過數組的entries
方法和解構返回數組的索引和對應的值:
for (let [index, elem] of arr.entries()) { console.log(index+'. '+elem); }
更多信息:for-of循環
es5中,指定參數默認值得這樣:
function foo(x, y) { x = x || 0; y = y || 0; ··· }
es6有個更簡潔的語法:
function foo(x=0, y=0) { ··· }
es6語法還一個優勢:參數默認值只能被undefined
觸發,而在es5中,則會被任何z爲false
的值觸發。
更多信息:參數默認值
在Javascript中,命名參數的廣泛方式是對象字面量:
selectEntries({ start: 0, end: -1 });
其等價實現:
function selectEntries(options) { var start = options.start || 0; var end = options.end || -1; var step = options.step || 1; ··· }
es6中,解構是語法更簡單:
function selectEntries({ start=0, end=-1, step=1 }) { ··· }
es5中使參數可選的作法是這樣的:
function selectEntries(options) { options = options || {}; // (A) var start = options.start || 0; var end = options.end || -1; var step = options.step || 1; ··· }
es6中,能夠指定{}
爲參數的默認值:
function selectEntries({ start=0, end=-1, step=1 } = {}) { ··· }
更多信息::模擬命名參數
es5中,若想讓方法或函數接受任意個數的參數,就必須使用指定的arguments
變量:
function logAllArguments() { for (var i=0; i < arguments.length; i++) { console.log(arguments[i]); } }
es6中,可使用...
操做達到一樣地效果:
function logAllArguments(...args) { for (let arg of args) { console.log(arg); } }
還有更nice的語法:
function format(pattern, ...args) { ··· }
而es5中的處理則相對笨拙:
function format() { var pattern = arguments[0]; var args = arguments.slice(1); ··· }
更多信息:Rest parameters
es5中,apply()
會將數組轉會成參數,es6中使用散佈操做符達到一樣地目的。
es5-->apply()
:
> Math.max.apply(null, [-1, 5, 11, 3]) 11
es6-->spread operator:
> Math.max(...[-1, 5, 11, 3]) 11
es5-->apply()
:
var arr1 = ['a', 'b']; var arr2 = ['c', 'd']; arr1.push.apply(arr1, arr2); // arr1 is now ['a', 'b', 'c', 'd']
es6-->spread operator:
let arr1 = ['a', 'b']; let arr2 = ['c', 'd']; arr1.push(...arr2); // arr1 is now ['a', 'b', 'c', 'd']
更多信息:spread operator
ES5 – concat():
var arr1 = ['a', 'b']; var arr2 = ['c']; var arr3 = ['d', 'e']; console.log(arr1.concat(arr2, arr3)); // [ 'a', 'b', 'c', 'd', 'e' ]
ES6 – spread operator:
let arr1 = ['a', 'b']; let arr2 = ['c']; let arr3 = ['d', 'e']; console.log([...arr1, ...arr2, ...arr3]); // [ 'a', 'b', 'c', 'd', 'e' ]
更多信息:spread operator
對於構造器語法,es6的類則更簡便。
es5中實現一個基本類以下:
function Person(name) { this.name = name; } Person.prototype.describe = function () { return 'Person called '+this.name; };
es6中,類提供了更簡潔的語法:
class Person { constructor(name) { this.name = name; } describe() { return 'Person called '+this.name; } }
es5實現了類的派生,下面是實現派生類的一種規範方法:
function Employee(name, title) { Person.call(this, name); // super(name) this.title = title; } Employee.prototype = Object.create(Person.prototype); Employee.prototype.constructor = Employee; Employee.prototype.describe = function () { return Person.prototype.describe.call(this) // super.describe() + ' (' + this.title + ')'; };
es6內置了類派生語法,要藉助extends
關鍵字:
class Employee extends Person { constructor(name, title) { super(name); this.title = title; } describe() { return super.describe() + ' (' + this.title + ')'; } }
更多信息:類
跟上面有點相似。es5中自定義error:
function MyError() { // Use Error as a function var superInstance = Error.apply(null, arguments); copyOwnPropertiesFrom(this, superInstance); } MyError.prototype = Object.create(Error.prototype); MyError.prototype.constructor = MyError;
es6經過派生實現:
class MyError extends Error { }
更多信心:Subclassing built-in constructors
語法上的差異。es5實現:
var obj = { foo: function () { ··· }, bar: function () { this.foo(); }, // trailing comma is legal in ES5 }
es6:
let obj = { foo() { ··· }, bar() { this.foo(); }, }
更多信息:方法定義
es5中利用對象來實現圖的數據結構,須要將對象的prototype
指向null
,並保證__proto__
上沒有對應的鍵。
var dict = Object.create(null); function countWords(word) { var escapedWord = escapeKey(word); if (escapedWord in dict) { dict[escapedWord]++; } else { dict[escapedWord] = 1; } } function escapeKey(key) { if (key.indexOf('__proto__') === 0) { return key+'%'; } else { return key; } }
es6則內置了Map數據結構;
let map = new Map(); function countWords(word) { let count = map.get(word) || 0; map.set(word, count + 1); }
更多信息:Maps and Sets
es5中,模塊系統是基於AMD或CommocJS語法。es6內置了模塊語法,但並無獲得Javascript引擎良好支持。
在CommonJS中,能夠這樣實現:
//------ lib.js ------ var sqrt = Math.sqrt; function square(x) { return x * x; } function diag(x, y) { return sqrt(square(x) + square(y)); } module.exports = { sqrt: sqrt, square: square, diag: diag, }; //------ main1.js ------ var square = require('lib').square; var diag = require('lib').diag; console.log(square(11)); // 121 console.log(diag(4, 3)); // 5
es6的語法是醬紫的:
//------ lib.js ------ export const sqrt = Math.sqrt; export function square(x) { return x * x; } export function diag(x, y) { return sqrt(square(x) + square(y)); } //------ main1.js ------ import { square, diag } from 'lib'; console.log(square(11)); // 121 console.log(diag(4, 3)); // 5
或者做爲一個對象導入:
//------ main2.js ------ import * as lib from 'lib'; // (A) console.log(lib.square(11)); // 121 console.log(lib.diag(4, 3)); // 5
Node.js繼承了CommonJS的語法,能從模塊導出單個值:
//------ myFunc.js ------ module.exports = function () { ··· }; //------ main1.js ------ var myFunc = require('myFunc'); myFunc();
es6經過export default
實現:
//------ myFunc.js ------ export default function () { ··· } // no semicolon! //------ main1.js ------ import myFunc from 'myFunc'; myFunc();
更多信息:Modules
相關文章:ECMAScript 6新特性介紹
譯文出處:Getting started with ECMAScript 6