

最近在做畢業(yè)設計,其中用到了一些 ES6 的語法,比如模塊的輸出引入,箭頭函數(shù),對象字面量的簡寫,等等。所性順便就學一下 ES6 的語法,做一個筆記總結。

let 和 const 命令
在 JavaScript 中變量作用域的基本單位總是function。如果你需要創(chuàng)建一個塊級作用域,除了普通的函數(shù)聲明以外最流行的方法就是使用立即被調用的函數(shù)表達式(IIFE)。
var a = 2;
(function IIFE(){
var a = 3;
? ? console.log( a );? // 3,a=3,只存在函數(shù)內部
})();
console.log( a );? ? ? // 2
在ES6中實現(xiàn)了塊級作用域,不需要我們再去借用函數(shù)來實現(xiàn)塊級作用域了。
為了更加語義化,我們習慣用 {} 包裹let和const命令,用來表示塊級作用域的范圍
聲明變量用let,聲明常量用const;const用于那些你有意地并且明顯地標識為不會改變的變量,具體使用什么應該視情況而定
let命令
var a = 2;
{
? let a = 3;
? console.log( a ); // 3
}
console.log( a );? ? ? // 2
不存在變量提升,變量一定要在聲明后使用,否則會報錯,存在暫時性死區(qū)
塊級作用域,(使得廣泛應用的立即執(zhí)行函數(shù)(IIFE)不在必要了
let不允許在相同的作用域內重復聲明一個變量
const命令
聲明一個常量,一旦定義不允許修改
{
? const a = 2;
? console.log( a ); // 2
? a = 3;? ? ? ? ? ? ? ? // TypeError!,一旦在聲明時被設定就不允許你改變了
}
注意:const聲明的值不會因為const而凍結或不可變,只是它的賦值被凍結了。如果這個值是一個復雜值,比如對象或數(shù)組,那么這個值的內容仍然是可以被修改的(變量a實際上沒有持有一個固定的數(shù)組;而是指向數(shù)組的恒定的引用。(引用類型賦值)數(shù)組本身可以自由變化。):
{
? const a = [1,2,3];
? a.push( 4 );
? console.log( a );? ? // [1,2,3,4]
? a = 42;? ? ? ? ? ? ? ? ? // TypeError!
}
const 一旦聲明常量,就必須立即初始化,不能留到以后賦值,在聲明時被設定就不允許你改變了
只在聲明所在的塊級作用域內有效,不能重復聲明常量
聲明的常量不提升,存在暫時性死區(qū),只能在聲明之后使用
const 不允許在相同的作用域內重復聲明一個變量
對象數(shù)組的擴散/收集
ES6引入了一個新的...操作符,它一般被稱作 擴散(spread) 或 剩余(rest) 操作符
function foo(x,y,z) {
? console.log( x, y, z );
}
foo( ...[1,2,3] );? //1 2 3 將...[1,2,3] 擴散成 x=1,y=2,z=3
var a = [2,3,4];
var b = [ 1, ...a, 5 ];
console.log( b ); //[1, 2, 3, 4, 5],相當于[1].concat( a, [5] )
...操作符可把她們擴散,同樣也可以把她們收集起來
function foo(...args) {
? console.log( args );
}
foo( 1, 2, 3, 4, 5); // [1,2,3,4,5],將1,2,3,4,5收集到...args里面。是一個參數(shù)數(shù)組
模板字符串
模板字符串是增強版的字符串,用反引號 ` 標識,他可以當做普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量;
使用反引號 `? 將整個字符串包裹起來,${}包裹一個變量或者表達式,如果變量沒有聲明,則報錯,大括號中的值不是字符串,將按照一定的規(guī)則轉化為字符串
如果在字符串中需要使用反引號,則需要在其前面用反斜杠轉義(如 \ `);
靜態(tài)字符串一律使用單引號或反引號,不使用雙引號,動態(tài)字符串使用反引號
function upper(s) {
? ? return s.toUpperCase();
}
let who = "reader";
let text =
`A very ${upper( "warm" )} welcome to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome to all of you READERS!
函數(shù)的擴展
ES6允許為函數(shù)的參數(shù)設置默認值,即直接寫在參數(shù)定義后面
function log(x,y='world'){
? console.log(x,y);
}
log('Hello');? //Hello world
參數(shù)變量是默認聲明的,所以不能使用let和const再次聲明 ( 因為let和const不能重復聲明變量 )
通常情況下,定義了默認值的參數(shù)應該是函數(shù)的尾參數(shù),因為這樣比較容易看出,到底是省略了哪些參數(shù),如果非尾部的參數(shù)設置默認值,實際上這個參數(shù)是無法省略的
ES6允許為函數(shù)的參數(shù)設置默認值表達式,即直接把參數(shù)寫成表達式
function bar(val) {
? console.log( "bar called!" );
? return y + val;
}
function foo(x = y + 3, z = bar( x )) {
? console.log( x, z );
}
let y = 5;
foo();? // "bar called"? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 8 13
foo( 10 );? // "bar called"? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 10 15
注意:
let w = 1, z = 2;
function foo( x = w + 1, y = x + 1, z = z + 1 ) {
? console.log( x, y, z );
}
foo();? // ReferenceError,因為在參數(shù)里面聲明了(他就沒向上尋找外部的作用域),而參數(shù)里面沒有初始化,所以直接使用會報錯
對象字面量擴展
一般情況的對象字面量聲明
let x=2,y=9,
? o={
? ? ? x:x,
? ? ? y:y
? },
? p={
? ? ? foo:function(){},
? ? ? bar:function(){}
? }
因為對象的屬性名和變量名一致,在ES6中我們可以使用簡寫(省略:x,:y,:function):
let x=2,y=9,
? o={
? ? ? x,
? ? ? y
? },
? p={
? ? ? foo(){},
? ? ? bar(){}
? }
注意:我們應當僅在永遠不需要將它們用于遞歸或事件綁定/解除時使用它們;否則會出現(xiàn)丟失函數(shù)的問題;
計算型屬性名
ES6為對象字面定義增加了一種語法,它允許你指定一個應當被計算的表達式,其結果就是被賦值屬性名。
let user='user_',
? ? o={
? ? ? ? [user+'foo']:function(){},
? ? ? ? [user+'bar']:function(){},
? ? };
console.log(o);? //Object {user_foo: function, user_bar: function}
箭頭函數(shù)
箭頭函數(shù)可以替換函數(shù)表達式,但是不能替換函數(shù)聲明;它們都是匿名函數(shù)表達式 —— 它們沒有可以用于遞歸或者事件綁定/解除的命名引用
如果箭頭函數(shù)的代碼部分多余一條語句,就要用大括號將其括起來,并使用return語句返回;
let foo = (x,y) => x + y;
let f3 = (x,y) => {
? ? let z = x * 2 + y;
? ? y++;
? ? x *= 3;
? ? return (x + y + z) / 2;
};
由于大括號被解析為代碼塊,所以如果箭頭函數(shù)直接返回一個對象,必須在對象外面加上括號
箭頭函數(shù)有幾個使用注意點
函數(shù)體內的this對象就是定義時所在的對象,而不是使用時所在的對象;this對象的指向是固定的
不可以當做構造函數(shù),即不能使用new命令,否則會拋出一個錯誤;因為箭頭函數(shù)沒有自己的this,導致內部的this就是外層代碼塊的this,所有沒有構造函數(shù);
不可使用arguments對象,該對象在函數(shù)體內不存在,如果要用,可以用rest參數(shù)替代
由于箭頭函數(shù)沒有自己的this,所以不能用call(),apply(),bind()這些方法去改變this的值;
在ES6中,默認會用嚴格模式,因此this不會自動指向window對象,而箭頭函數(shù)本身沒有this,因此this就只能是undefined;
簡單的,單行的,不會復用的函數(shù),建議采用箭頭函數(shù),如果函數(shù)體較為復雜,行數(shù)比較多,還是應該使用傳統(tǒng)的函數(shù)寫法
尾調用優(yōu)化
函數(shù)調用會形成一個"調用記錄",又稱"調用幀",如果函數(shù)在函數(shù) A 的內部調用函數(shù) B ,那么在 A 的調用幀上方形成一個 B 的調用幀,等到 B 運行結束,將結果返回 A ,B 的調用幀才會結束;
尾調用由于是函數(shù)的最后一步,不需要保留外層函數(shù)的調用幀,因為調用位置,內部變量等信息都不會再用,直接內層函數(shù)的調用幀取代外層函數(shù)即可;可以節(jié)省內存
Module
模塊功能主要由兩個命令構成import和export,并且他們都必須總是出現(xiàn)在它們分別被使用之處的頂層作用域。export命令用于規(guī)定模塊的對外接口,import命令用于輸入其他模塊提供的功能;在模塊中沒有全局作用域。
export命令
一個模塊就是一個獨立的文件,該文件內部的所有變量,外部無法獲取,如果希望外部能夠讀取,模塊內部的某個變量,就必須使用export關鍵字輸出該變量
export function foo() {
? ? // ..
}
import命令
使用export命令定義了模塊的對外接口以后,其他js文件可以通過import命令加載這個模塊文件
import foo form './foo';
表示加載foo.js文件,import命令接受一個對象(用大括號表示),里面指定要從其他模塊導入的變量名;大括號中變量名必須與被導入的模塊(foo.js)對外接口的名稱相同
import命令具有提升效果,會提升到整個模塊的頭部首先執(zhí)行;
如果在一個模塊中先后輸入后輸出同一個模塊,import和export語句寫在一起,不建議那樣寫;
module命令可以取代import語句,達到整體輸入模塊的作用;
module 命令后面跟一個變量,表示輸入的模塊定義在該變量上
export default命令為模塊指定默認輸出,其他模塊在加載該模塊時, 默認輸出是一個函數(shù),import命令可以為該匿名函數(shù)指定任意名字;import命令后面不使用大括號;
export default命令只用于指定模塊的默認輸出,顯然一個模塊只能有一個默認輸出,因此export default命令只能使用一次,所以import命令后面才不加大括號,因為只可能對于一個方法
暫時就先介紹到這里;等畢設差不多做完的時候,就準備著手找工作。
我要糾正我的一個小小的錯誤,對象解構不是ES6 的而是ES9的內容,感謝 justjava 提出來啦,不然我又該去誤導別人啦!感謝 justjava,以后我會多關注一些相關的 proposal 。盡量不去犯一些常識性的錯誤
變量的解構賦值
從一個數(shù)組中取得索引的值,或從一個對象中取得屬性并手動賦值可以被認為是 結構化賦值,比如
function foo() {
? return [1,2,3];
}
let tmp = foo(),
? ? a = tmp[0], b = tmp[1], c = tmp[2];
console.log( a, b, c );? ? ? ? ? ? // 1 2 3
如果剔除中間變量 tmp 而直接進行賦值稱為解構賦值
function foo() {
? return [1,2,3];
}
let [a,b,c]=foo();
console.log(a,b,c); // 1 2 3
從數(shù)組和對象中提取值,對變量進行賦值,被稱為解構,本質上屬于“ 模式匹配 ”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值
數(shù)組解構:
如果右邊的少于左邊的參數(shù),視為解構不成功,變量值就等于 undefined
let [a,b,c,d]=['a'];
console.log(a,b,c,d);? //a undefined undefined undefined
如果右邊的多余于左邊的參數(shù),視為不完全解構,多余的值將會被忽略
let [a,b,c,d]=[1,2,3,4,5,6];
console.log(a,b,c,d);? //1 2 3 4
對象解構:
對象解構與數(shù)組解構有一個重要的不同,數(shù)組的元素是按照次序排列的,對象的屬性沒有次序,變量必須與屬性同名才能取到正確的值
let {bar,foo}={foo:'111',bar:'222'}
console.log(bar,foo);? //222 111
注意:上面我們使用了對象屬性賦值的簡寫,即如果屬性名與你想要聲明的變量名一致,我們可以使用簡寫,上面例子等同于
let {bar:bar,foo:bar}={foo:'111',bar:'222'}
console.log(bar,foo);? //222 111