ES全稱ECMAScript,ECMAScript是ECMA制定的標準化腳本語言。目前JavaScript使用的ECMAScript版本爲ECMAScript-262。程序員
ECMAScript 標準創建在一些原有的技術上,最爲著名的是 JavaScript (網景) 和 JScript (微軟)。它最初由網景的 Brendan Eich 發明,第一次出現是在網景的 Navigator 2.0 瀏覽器上。Netscape 2.0 以及微軟 Internet Explorer 3.0 後序的全部瀏覽器上都有它的身影。編程
ECMAScript版本 | 發佈時間 | 新增特性 |
---|---|---|
ECMAScript 2009(ES5) | 2009年11月 | 擴展了Object、Array、Function的功能等 |
ECMAScript 2015(ES6) | 2015年6月 | 類,模塊化,箭頭函數,函數參數默認值等 |
ECMAScript 2016(ES7) | 2016年3月 | includes,指數操做符 |
ECMAScript 2017(ES8) | 2017年6月 | sync/await,Object.values(),Object.entries(),String padding等 |
下面會介紹幾個比較經常使用的新特性:數組
不存在變量提高,必須先定義後使用promise
console.log(foo);//ReferenceError let foo = 3;
暫時性死區 只要塊級做用域內存在let命令,他聲明的變量就是綁定在這個區域,再也不受外部影響;ES6 明確規定,若是區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量,就會報錯。瀏覽器
if (true) { // TDZ開始 tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ結束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123 }
const命令只是保證變量指向的地址不變,並不保證改地址的數據不變異步
const foo = {}; foo.prop = 123; foo.prop;//123
ES6容許使用箭頭(=>)定義函數。 ide
=>不僅是關鍵字function的簡寫,它還帶來了其它好處。箭頭函數與包圍它的代碼共享同一個this,能幫你很好的解決this的指向問題。有經驗的JavaScript開發者都熟悉諸如var self = this;或var that = this這種引用外圍this的模式。但藉助=>,就不須要這種模式了。模塊化
若是箭頭函數不須要參數或者須要多個參數,就是用圓括號表明參數部分。異步編程
let sum = (num1,num2) => { return num1+num2 }
箭頭函數的特色:函數
//箭頭函數中this指向固定 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
ES6容許按照必定的模式,從數組和對象中提取值,對變量進行賦值,這被稱爲 解構
數組解構
let [x,y,z] = new Set(["a","b","c"]); x //a let [foo = true] = []; foo //true let [x,y='b'] = [a]; let [x,y='b'] = [a,undefined]; //以上兩種輸出都是 x //a y //b
對象解構
對象的解構與數組的解構有一個重要的不一樣;數組的元素是按次序排列的,變量的取之由他的位置決定;而對象的屬性是沒有次序的,變量必須與屬性同名,才能取到正確的值
let {bar,foo} = {foo:"aaa",bar:"bbb"}; bar // bbb foo //aaa let {baz,foo} = {foo:"aaa",bar:"bbb"}; baz //undefined 若是變量名與屬性名不一致 let {first:f, last:l} = {first:"hello", last:"bye"}; first //undefined f //hello last //undefined l //bye
也就是說對象解構賦值的內部機制,是先找到同名屬性,而後在賦值給對應的變量,真正被賦值的是後者,而不是前者
參數默認值能夠與解構賦值的默認值結合使用
function foo(x,y=5){ console.log(x,y); } foo({});//undefined,5 foo(1);//1,5 foo(1,2)//1,2
模版字符串是加強版的字符串,用反引號(`)標識;他能夠看成普通字符串使用,也能夠用來定義多行字符串,或者在字符串中嵌入變量
let name="Tom",time="today"; `hello ${name},how arw your ${time}`
大括號裏面能夠聽任意的JavaScript表達式,能夠進行運算,以及引用對象屬性。
let x = 1; let y = 2; `${x}+${y}=${x+y}`//1+2=3 let obj = {x:1,y:3}; `${obj.x+obj.y}` // 4
模版字符串中還能調用函數
function fn(){ return "hehe"; } `test ${fn()}` // test hehe
多行字符串
//ES5中 var roadPoem = 'Then took the other, as just as fair,nt' + 'And having perhaps the better claimnt' + 'Because it was grassy and wanted wear,nt' + 'Though as for that the passing therent' + 'Had worn them really about the same,nt'; //ES6 let roadPoem = `Then took the other, as just as fair, And having perhaps the better claim Because it was grassy and wanted wear, Though as for that the passing there
咱們之前不得不經過下面方式來定義默認參數
var link = function (height, color, url) { var height = height || 50; var color = color || 'red'; var url = url || 'http://azat.co'; ... }
一切工做都是正常的,直到參數值是0後,就有問題了,由於在JavaScript中,0表示false,它是默認被hard-coded的值,而不能變成參數自己的值。固然,若是你非要用0做爲值,咱們能夠忽略這一缺陷而且使用邏輯OR就好了!但在ES6,咱們能夠直接把默認值放在函數申明裏:
let link = function(height = 50, color = 'red', url = 'http://azat.co') { ... }
ES5中對象必須包含屬性和值
const name='Ming',age='18',city='Shanghai'; const student = { name:name, age:age, city:city }; console.log(student);//{name: "Ming", age: "18", city: "Shanghai"}
使用ES6的話就會變得很是簡潔
const name='Ming',age='18',city='Shanghai'; const student = { name, age, city }; console.log(student);//{name: "Ming", age: "18", city: "Shanghai"}
Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最先提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。
下面是一個簡單的用setTimeout()實現的異步延遲加載函數:
setTimeout(function(){ console.log('Test!'); }, 1000);
在ES6中,咱們能夠用promise重寫:
let wait1000 = new Promise((resolve, reject)=> { setTimeout(resolve, 1000); }).then(()=> { console.log('Yay!'); });
const promise = new Promise((resolve, reject)=> { // ... some code if (/* 異步操做成功 */){ resolve(value); } else { reject(error); } });
Promise構造函數接受一個函數做爲參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由 JavaScript 引擎提供,不用本身部署。
resolve函數的做用是,將Promise對象的狀態從「未完成」變爲「成功」(即從 pending 變爲 resolved),在異步操做成功時調用,並將異步操做的結果,做爲參數傳遞出去;reject函數的做用是,將Promise對象的狀態從「未完成」變爲「失敗」(即從 pending 變爲 rejected),在異步操做失敗時調用,並將異步操做報出的錯誤,做爲參數傳遞出去。
Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數。
promise.then((value)=> { // success }, (error)=> { // failure });
then方法能夠接受兩個回調函數做爲參數。第一個回調函數是Promise對象的狀態變爲resolved時調用,第二個回調函數是Promise對象的狀態變爲rejected時調用。其中,第二個函數是可選的,不必定要提供。這兩個函數都接受Promise對象傳出的值做爲參數。
JavaScript 語言中,生成實例對象的傳統方法是經過構造函數。下面是一個例子。
function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; }; var p = new Point(1, 2);
上面這種寫法跟傳統的面嚮對象語言(好比 C++ 和 Java)差別很大,很容易讓新學習這門語言的程序員感到困惑。
ES6 提供了更接近傳統語言的寫法,引入了 Class(類)這個概念,做爲對象的模板。經過class
關鍵字,能夠定義類。
基本上,ES6 的class
能夠看做只是一個語法糖,它的絕大部分功能,ES5 均可以作到,新的class
寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。上面的代碼用 ES6 的class
改寫,就是下面這樣。
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } }
上面代碼定義了一個「類」,能夠看到裏面有一個constructor
方法,這就是構造方法,而this
關鍵字則表明實例對象。也就是說,ES5 的構造函數Point
,對應 ES6 的Point
類的構造方法。
Point
類除了構造方法,還定義了一個toString
方法。注意,定義「類」的方法的時候,前面不須要加上function
這個關鍵字,直接把函數定義放進去了就能夠了。另外,方法之間不須要逗號分隔,加了會報錯。
衆所周知,在ES6之前JavaScript並不支持本地的模塊。人們想出了AMD,RequireJS,CommonJS以及其它解決方法。如今ES6中能夠用模塊import 和export 操做了。
在ES5中,你能夠在 <script>中直接寫能夠運行的代碼(簡稱IIFE),或者一些庫像AMD。然而在ES6中,你能夠用export導入你的類。下面舉個例子,在ES5中,module.js有port變量和getAccounts 方法:
module.exports = { port: 3000, getAccounts: function() { ... } }
在ES5中,main.js須要依賴require('module') 導入module.js:
var service = require('module.js'); console.log(service.port); // 3000
但在ES6中,咱們將用export 和 import。例如,這是咱們用ES6 寫的module.js文件庫:
export var port = 3000; export function getAccounts(url) { ... }
若是用ES6來導入到文件main.js中,咱們需用import 語法,例如:
import {port, getAccounts} from 'module'; console.log(port); // 3000
或者咱們能夠在main.js中把整個模塊導入, 並命名爲 service:
import * as service from 'module'; console.log(service.port); // 3000