1.介紹 node
總的來講,ES6是在ES2015的基礎上改變了一些書寫方式,開放了更多API,這樣作的目的最終仍是爲了貼合實際開發的須要。若是說一門編程語言的誕生是天才的構思和實現,那它的發展無疑就是不斷填坑的歷史。ES6正是爲了填一些坑。git
我對ES6語法的學習,主要在瀏覽器端,參考阮一峯大神的ES6入門教程,添加了一些我的理解的註釋和遇到的小問題,歡迎批評指正,共同進步。es6
瀏覽器端引用的依賴文件和本文案例 可在 https://github.com/chanceLe/ES6-Basic-Syntax 找到。github
2.基礎部分編程
2.1let和const關鍵字瀏覽器
let命令聲明變量,相似var,但所聲明的變量只在let代碼塊有效。 編程語言
{ let a = 1; var b = 2; } console.log(b); console.log(a); //報錯,找不到。 //for循環的計數器,就很適合用let for(let i=0;i<5;i++){ console.log(i); } //上面的代碼的計數器i,只在for循環體內有效。
{}在ES6中用來造成塊級做用域,後邊會說到。 函數
var a = []; for(var i=0;i<10;i++){ a[i] = function(){ console.log(i); } }
a[6](); //10 到九循環完,又加了1,換成let會獲得指望結果。
var聲明的變量全局範圍內都有效。因此每次循環,新的i值都會覆蓋舊值
let聲明的僅在塊級做用域內有效,最後輸出6
let不會發生變量提高的現象,因此必定要在定義後使用,不然報錯。
暫時性死區:只要塊級做用域內存在let命令,它所聲明的變量就綁定這個區域,再也不受外部影響。學習
var tmp = 123; if(true){ tmp = "abc"; console.log(tmp,"11"); //"abc" let tmp; } console.log(tmp,"22"); //"123"
書上說,若是區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉
做用域,凡是聲明以前使用的,都會報錯。spa
實際狀況,let不會報錯,const會報錯(這可能跟瀏覽器端轉碼有關,版本爲5)。
有些死區比較隱蔽,不太容易發現:
function bar(x=y,y=2){ return [x,y]; } console.log(bar()); //書上說這裏因爲y沒有定義,應該報錯,實際是 [undefined,2] function bar2(x=2,y=x){ return [x,y]; } console.log(bar2()); //[2,2]正常
不容許重複聲明,let不容許在相同做用域內,重複聲明同一個變量:
function fun(){ let a = 10; // var a = 5; //報錯。 // let a = 1; //報錯 }
不能在函數內部從新聲明參數:
function fun1(arg){ // let arg; //報錯 { let arg; //不報錯 } }
const命令
聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
同時也說明,一旦聲明,就要當即初始化,不然也報錯。
const PI = 3.1415; console.log(PI); // PI = 3; //報錯 只讀的 // const circle; //報錯,一旦聲明,必須當即初始化。 /* * const的做用域與let命令相同:只在聲明所在的塊級做用域有效。 */ if(true){ const m = 5; } // console.log(m); //未定義
與let類似:
const命令聲明的常量也不提高,一樣存在暫時性死區,只能在聲明的位置後使用。
也不能夠重複聲明。
對於複合類型的變量,變量名不指向數據,而是指向數據所在的地址。const命令只
是保證變量名指向的地址不變,並不保證該地址的數據不變,因此將一個對象聲明爲常量,
必須很是當心。
const foo = {}; foo.prop = 123; console.log(foo.prop); //上面的常量foo存儲的是對象的地址,這個地址不可變,但依然能夠添加屬性。 const a = []; a.push("hello"); a.length = 0; // a = ["Dave"] //報錯,賦值就是更換地址,不行的。 //若是真的想把對象凍結,應該使用Object.freeze方法。 const foo2 = Object.freeze({}); //常規模式下,下面一行不起做用 //嚴格模式下,會報錯 foo.prop = 123;
ES5只有兩種聲明變量的方法:var和function。
ES6有6種:var function let const class import
全局對象屬性:
全局對象是最頂層的對象,在瀏覽器環境下指的是window對象,在node指的是
global對象。ES5中,全局對象的屬性和全局變量是等價的。
未聲明的全局變量,自動成爲全局對象window的屬性,這被認爲是js的最大敗筆。
ES6爲了改變這一點,一方面規定,爲了保持兼容性,var命令和function命令聲明的全局變量,
依舊是全局對象的屬性,另外一方面規定,let,const,class命令聲明的全局變量不屬於全局對象的
屬性。也就是說,從ES6開始,全局變量將逐漸與全局對象的屬性脫鉤。
2.2塊級做用域:
ES5只有全局做用域和函數做用域,沒有塊級做用域,有不少不合理場景:
1.內層變量可能會覆蓋外層變量。
var tmp = new Date(); function f(){ console.log(tmp); if(false){ var tmp = "hello world!"; } } f(); //undefined 聲明提高,後邊的定義把前邊的覆蓋掉了。
2.用來計數的循環變量泄漏爲全局變量。典型的var定義的循環,上邊有代碼體現。
let實際上爲js新增了塊級做用域。下面的代碼兩個代碼塊都聲明瞭n,運行輸出5,表示外層代碼不受內層代碼塊的影響。若是是var定義,就會收到影響,輸出10;
function f1(){ let n = 5; if(true){ let n = 10; } console.log(n); } f1();
//es6容許塊級做用域的任意嵌套: {{{{{ let insane = "hello world" }}}}} //上面代碼使用了五層塊級做用域,外部不能訪問內部的變量。 //塊級做用域實際上使得普遍應用的當即執行匿名函數(IIFE)再也不須要了。 //IIFE寫法 (function(){ })() //塊級做用域寫法 { } /*
* 塊級做用域與函數聲明: * ES5規定,函數只能在頂層做用域和函數做用域之中聲明,不能在塊做用域中聲明, * 狀況一: * if(true){ * function(){} * } * 狀況二: * try{ * function(){} * }
這兩種狀況,根據ES5的規定都是非法的。可是瀏覽器沒有遵照這個規定,能夠運行,在嚴格
模式下,仍是會報錯。
ES6引入了塊級做用域,明確容許在塊級做用域中聲明函數。
塊級做用域中,函數聲明語句的行爲相似於let,在塊級做用域以外,不能夠引用。
由於塊級做用域對做用域以外沒有影響,這個差別會對老代碼產生很大影響,爲了減輕這個不兼容
問題,ES6在附錄B中規定,瀏覽器能夠不遵照上面的規定,有本身的行爲方式。
1.容許在塊級做用域內聲明函數。 2.函數聲明相似於var,即會提高到全局做用域或函數做用域的頭部。 3.同時,函數聲明還會提高到所在塊級做用域的頭部。 上面的3個規則只對ES6 的瀏覽器實現有效,其餘環境的實現不用遵照,仍是將塊級做用域當作let處理。 考慮到環境致使的行爲差別太大,應該避免在塊級做用域內聲明函數。若是確實須要,也應該寫成函數表達式。 ES6的塊級做用域容許聲明函數的規則,只在使用大括號的狀況下成立,沒有使用大括號,會報錯。