ES6 語法 上篇

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

let 和 const 命令

在 JavaScript 中變量作用域的基本單位總是function。如果你需要?jiǎng)?chuàng)建一個(gè)塊級作用域,除了普通的函數(shù)聲明以外最流行的方法就是使用立即被調(diào)用的函數(shù)表達(dá)式(IIFE)。

var a = 2;

(function IIFE(){

var a = 3;

? ? console.log( a );? // 3,a=3,只存在函數(shù)內(nèi)部

})();

console.log( a );? ? ? // 2

在ES6中實(shí)現(xiàn)了塊級作用域,不需要我們再去借用函數(shù)來實(shí)現(xiàn)塊級作用域了。

為了更加語義化,我們習(xí)慣用 {} 包裹let和const命令,用來表示塊級作用域的范圍

聲明變量用let,聲明常量用const;const用于那些你有意地并且明顯地標(biāo)識為不會改變的變量,具體使用什么應(yīng)該視情況而定

let命令

var a = 2;

{

? let a = 3;

? console.log( a ); // 3

}

console.log( a );? ? ? // 2

不存在變量提升,變量一定要在聲明后使用,否則會報(bào)錯(cuò),存在暫時(shí)性死區(qū)

塊級作用域,(使得廣泛應(yīng)用的立即執(zhí)行函數(shù)(IIFE)不在必要了

let不允許在相同的作用域內(nèi)重復(fù)聲明一個(gè)變量

const命令

聲明一個(gè)常量,一旦定義不允許修改

{

? const a = 2;

? console.log( a ); // 2

? a = 3;? ? ? ? ? ? ? ? // TypeError!,一旦在聲明時(shí)被設(shè)定就不允許你改變了

}

注意:const聲明的值不會因?yàn)閏onst而凍結(jié)或不可變,只是它的賦值被凍結(jié)了。如果這個(gè)值是一個(gè)復(fù)雜值,比如對象或數(shù)組,那么這個(gè)值的內(nèi)容仍然是可以被修改的(變量a實(shí)際上沒有持有一個(gè)固定的數(shù)組;而是指向數(shù)組的恒定的引用。(引用類型賦值)數(shù)組本身可以自由變化。):

{

? const a = [1,2,3];

? a.push( 4 );

? console.log( a );? ? // [1,2,3,4]

? a = 42;? ? ? ? ? ? ? ? ? // TypeError!

}

const 一旦聲明常量,就必須立即初始化,不能留到以后賦值,在聲明時(shí)被設(shè)定就不允許你改變了

只在聲明所在的塊級作用域內(nèi)有效,不能重復(fù)聲明常量

聲明的常量不提升,存在暫時(shí)性死區(qū),只能在聲明之后使用

const 不允許在相同的作用域內(nèi)重復(fù)聲明一個(gè)變量

對象數(shù)組的擴(kuò)散/收集

ES6引入了一個(gè)新的...操作符,它一般被稱作 擴(kuò)散(spread) 或 剩余(rest) 操作符

function foo(x,y,z) {

? console.log( x, y, z );

}

foo( ...[1,2,3] );? //1 2 3 將...[1,2,3] 擴(kuò)散成 x=1,y=2,z=3

var a = [2,3,4];

var b = [ 1, ...a, 5 ];

console.log( b ); //[1, 2, 3, 4, 5],相當(dāng)于[1].concat( a, [5] )

...操作符可把她們擴(kuò)散,同樣也可以把她們收集起來

function foo(...args) {

? console.log( args );

}

foo( 1, 2, 3, 4, 5); // [1,2,3,4,5],將1,2,3,4,5收集到...args里面。是一個(gè)參數(shù)數(shù)組

模板字符串

模板字符串是增強(qiáng)版的字符串,用反引號 ` 標(biāo)識,他可以當(dāng)做普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量;

使用反引號 `? 將整個(gè)字符串包裹起來,${}包裹一個(gè)變量或者表達(dá)式,如果變量沒有聲明,則報(bào)錯(cuò),大括號中的值不是字符串,將按照一定的規(guī)則轉(zhuǎn)化為字符串

如果在字符串中需要使用反引號,則需要在其前面用反斜杠轉(zhuǎn)義(如 \ `);

靜態(tài)字符串一律使用單引號或反引號,不使用雙引號,動(dòng)態(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ù)的擴(kuò)展

ES6允許為函數(shù)的參數(shù)設(shè)置默認(rèn)值,即直接寫在參數(shù)定義后面

function log(x,y='world'){

? console.log(x,y);

}

log('Hello');? //Hello world

參數(shù)變量是默認(rèn)聲明的,所以不能使用let和const再次聲明 ( 因?yàn)閘et和const不能重復(fù)聲明變量 )

通常情況下,定義了默認(rèn)值的參數(shù)應(yīng)該是函數(shù)的尾參數(shù),因?yàn)檫@樣比較容易看出,到底是省略了哪些參數(shù),如果非尾部的參數(shù)設(shè)置默認(rèn)值,實(shí)際上這個(gè)參數(shù)是無法省略的

ES6允許為函數(shù)的參數(shù)設(shè)置默認(rèn)值表達(dá)式,即直接把參數(shù)寫成表達(dá)式

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,因?yàn)樵趨?shù)里面聲明了(他就沒向上尋找外部的作用域),而參數(shù)里面沒有初始化,所以直接使用會報(bào)錯(cuò)

對象字面量擴(kuò)展

一般情況的對象字面量聲明

let x=2,y=9,

? o={

? ? ? x:x,

? ? ? y:y

? },

? p={

? ? ? foo:function(){},

? ? ? bar:function(){}

? }

因?yàn)閷ο蟮膶傩悦妥兞棵恢?,在ES6中我們可以使用簡寫(省略:x,:y,:function):

let x=2,y=9,

? o={

? ? ? x,

? ? ? y

? },

? p={

? ? ? foo(){},

? ? ? bar(){}

? }

注意:我們應(yīng)當(dāng)僅在永遠(yuǎn)不需要將它們用于遞歸或事件綁定/解除時(shí)使用它們;否則會出現(xiàn)丟失函數(shù)的問題;

計(jì)算型屬性名

ES6為對象字面定義增加了一種語法,它允許你指定一個(gè)應(yīng)當(dāng)被計(jì)算的表達(dá)式,其結(jié)果就是被賦值屬性名。

let user='user_',

? ? o={

? ? ? ? [user+'foo']:function(){},

? ? ? ? [user+'bar']:function(){},

? ? };

console.log(o);? //Object {user_foo: function, user_bar: function}

箭頭函數(shù)

箭頭函數(shù)可以替換函數(shù)表達(dá)式,但是不能替換函數(shù)聲明;它們都是匿名函數(shù)表達(dá)式 —— 它們沒有可以用于遞歸或者事件綁定/解除的命名引用

如果箭頭函數(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ù)直接返回一個(gè)對象,必須在對象外面加上括號

箭頭函數(shù)有幾個(gè)使用注意點(diǎn)

函數(shù)體內(nèi)的this對象就是定義時(shí)所在的對象,而不是使用時(shí)所在的對象;this對象的指向是固定的

不可以當(dāng)做構(gòu)造函數(shù),即不能使用new命令,否則會拋出一個(gè)錯(cuò)誤;因?yàn)榧^函數(shù)沒有自己的this,導(dǎo)致內(nèi)部的this就是外層代碼塊的this,所有沒有構(gòu)造函數(shù);

不可使用arguments對象,該對象在函數(shù)體內(nèi)不存在,如果要用,可以用rest參數(shù)替代

由于箭頭函數(shù)沒有自己的this,所以不能用call(),apply(),bind()這些方法去改變this的值;

在ES6中,默認(rèn)會用嚴(yán)格模式,因此this不會自動(dòng)指向window對象,而箭頭函數(shù)本身沒有this,因此this就只能是undefined;

簡單的,單行的,不會復(fù)用的函數(shù),建議采用箭頭函數(shù),如果函數(shù)體較為復(fù)雜,行數(shù)比較多,還是應(yīng)該使用傳統(tǒng)的函數(shù)寫法

尾調(diào)用優(yōu)化

函數(shù)調(diào)用會形成一個(gè)"調(diào)用記錄",又稱"調(diào)用幀",如果函數(shù)在函數(shù) A 的內(nèi)部調(diào)用函數(shù) B ,那么在 A 的調(diào)用幀上方形成一個(gè) B 的調(diào)用幀,等到 B 運(yùn)行結(jié)束,將結(jié)果返回 A ,B 的調(diào)用幀才會結(jié)束;

尾調(diào)用由于是函數(shù)的最后一步,不需要保留外層函數(shù)的調(diào)用幀,因?yàn)檎{(diào)用位置,內(nèi)部變量等信息都不會再用,直接內(nèi)層函數(shù)的調(diào)用幀取代外層函數(shù)即可;可以節(jié)省內(nèi)存

Module

模塊功能主要由兩個(gè)命令構(gòu)成import和export,并且他們都必須總是出現(xiàn)在它們分別被使用之處的頂層作用域。export命令用于規(guī)定模塊的對外接口,import命令用于輸入其他模塊提供的功能;在模塊中沒有全局作用域。

export命令

一個(gè)模塊就是一個(gè)獨(dú)立的文件,該文件內(nèi)部的所有變量,外部無法獲取,如果希望外部能夠讀取,模塊內(nèi)部的某個(gè)變量,就必須使用export關(guān)鍵字輸出該變量

export function foo() {

? ? // ..

}

import命令

使用export命令定義了模塊的對外接口以后,其他js文件可以通過import命令加載這個(gè)模塊文件

import foo form './foo';

表示加載foo.js文件,import命令接受一個(gè)對象(用大括號表示),里面指定要從其他模塊導(dǎo)入的變量名;大括號中變量名必須與被導(dǎo)入的模塊(foo.js)對外接口的名稱相同

import命令具有提升效果,會提升到整個(gè)模塊的頭部首先執(zhí)行;

如果在一個(gè)模塊中先后輸入后輸出同一個(gè)模塊,import和export語句寫在一起,不建議那樣寫;

module命令可以取代import語句,達(dá)到整體輸入模塊的作用;

module 命令后面跟一個(gè)變量,表示輸入的模塊定義在該變量上

export default命令為模塊指定默認(rèn)輸出,其他模塊在加載該模塊時(shí), 默認(rèn)輸出是一個(gè)函數(shù),import命令可以為該匿名函數(shù)指定任意名字;import命令后面不使用大括號;

export default命令只用于指定模塊的默認(rèn)輸出,顯然一個(gè)模塊只能有一個(gè)默認(rèn)輸出,因此export default命令只能使用一次,所以import命令后面才不加大括號,因?yàn)橹豢赡軐τ谝粋€(gè)方法

閱讀原文

暫時(shí)就先介紹到這里;等畢設(shè)差不多做完的時(shí)候,就準(zhǔn)備著手找工作。

我要糾正我的一個(gè)小小的錯(cuò)誤,對象解構(gòu)不是ES6 的而是ES9的內(nèi)容,感謝 justjava 提出來啦,不然我又該去誤導(dǎo)別人啦!感謝 justjava,以后我會多關(guān)注一些相關(guān)的 proposal 。盡量不去犯一些常識性的錯(cuò)誤

變量的解構(gòu)賦值

從一個(gè)數(shù)組中取得索引的值,或從一個(gè)對象中取得屬性并手動(dòng)賦值可以被認(rèn)為是 結(jié)構(gòu)化賦值,比如

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 而直接進(jìn)行賦值稱為解構(gòu)賦值

function foo() {

? return [1,2,3];

}

let [a,b,c]=foo();

console.log(a,b,c); // 1 2 3

從數(shù)組和對象中提取值,對變量進(jìn)行賦值,被稱為解構(gòu),本質(zhì)上屬于“ 模式匹配 ”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應(yīng)的值

數(shù)組解構(gòu):

如果右邊的少于左邊的參數(shù),視為解構(gòu)不成功,變量值就等于 undefined

let [a,b,c,d]=['a'];

console.log(a,b,c,d);? //a undefined undefined undefined

如果右邊的多余于左邊的參數(shù),視為不完全解構(gòu),多余的值將會被忽略

let [a,b,c,d]=[1,2,3,4,5,6];

console.log(a,b,c,d);? //1 2 3 4

對象解構(gòu):

對象解構(gòu)與數(shù)組解構(gòu)有一個(gè)重要的不同,數(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,565評論 0 13
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評論 19 139
  • 一、你不知道的JavaScript 1、作用域 作用域 LHS RHS RHS查詢與簡單地查找某個(gè)變量的值別無二...
    頂兒響叮當(dāng)閱讀 403評論 0 0
  • let 和 const 命令 let 命令 塊級作用域 const 命令 頂層對象的屬性 gl...
    安小明閱讀 1,041評論 0 0
  • let 命令 塊級作用域 const 命令 頂層對象的屬性 global 對象 let 命令 基本用法 ES6 新...
    嘉奇呦_nice閱讀 1,695評論 0 2

友情鏈接更多精彩內(nèi)容