ES6可以說(shuō)是一個(gè)泛指,指5.1版本以后的JavaScript的下一代標(biāo)準(zhǔn),涵蓋了ES2015,ES2016,ES2017等;亦指下一代JavaScript語(yǔ)言。
背景
嗯~ES6的語(yǔ)法有什么好談的,無(wú)聊了吧?
確實(shí),語(yǔ)法糖的東西真的是學(xué)起來(lái)如嚼蠟 -- 淡無(wú)味;但是要用別人的東西來(lái)開(kāi)發(fā)的,你學(xué)還是學(xué)呢?
所以,還是簡(jiǎn)單談下吧...
本次的ES6語(yǔ)法的匯總總共分為上、中、下三篇,本篇文章為上篇。
var、let和const
var是之前就有的了,在這里提出來(lái)主要是為了比較其和let與const。
區(qū)別
1. 塊級(jí)作用域
for(vari =0; i <3; i++) {setTimeout(()=>{console.log(i);// 輸出3個(gè)3},0)}復(fù)制代碼
解析:變量i是var聲明的,在全局范圍內(nèi)是都有效,全局只有一個(gè)變量i。每次循環(huán),變量的值會(huì)發(fā)生改變。循環(huán)內(nèi)的i是指向全局的i。
for(leti =0; i <3; i++) {setTimeout(()=>{console.log(i);// 輸出0, 1, 2},0)}復(fù)制代碼
解析:變量i是let聲明的,當(dāng)前的i只在本輪循環(huán)有效,所以每次循環(huán)的i其實(shí)都是一個(gè)新變量。JavaScript引擎內(nèi)部會(huì)記住上一輪的值,初始化本輪的變量i時(shí),就在上一輪循環(huán)的基礎(chǔ)上進(jìn)行計(jì)算。
2. 不存在變量提升
console.log(a);// undefinedvara =100;復(fù)制代碼
var命令會(huì)發(fā)生變量提升現(xiàn)象,即變量可以在聲明之前使用,值為undefined;而let糾正了這種行為,不能產(chǎn)生變量提升。
console.log(a);// 報(bào)錯(cuò)leta =100;復(fù)制代碼
3. 暫時(shí)性死區(qū)
只要塊級(jí)作用域內(nèi),存在let命令,它所聲明的變量就綁定(binding)在這個(gè)區(qū)域,不再受外部影響。
如:
vartemp =123;if(true) {temp ='abc';// 引入錯(cuò)誤lettemp; }復(fù)制代碼
在上面中,if后面的大括號(hào)內(nèi)容就形成了一個(gè)區(qū)域。而temp此時(shí)是找不到外層的,因?yàn)閮?nèi)部有個(gè)temp且你在內(nèi)部let temp聲明前賦值了。
在看一個(gè)隱晦的例子:
functionbar(x = y, y =2){return[x, y]}bar();// 報(bào)錯(cuò)復(fù)制代碼
在上面的例子中bar里面進(jìn)行賦值操作的時(shí)候,就產(chǎn)生了一個(gè)封閉的區(qū)域了,可以認(rèn)為x 和 y通過(guò)let聲明,可是上面的問(wèn)題是,x = y的引用在y = 2的聲明之前。
可以修正如下:
functionbar(y =2, x = y){return[x, y];}bar();// [2, 2]復(fù)制代碼
4. 不可重復(fù)聲明
vara =100;vara =1000;console.log(a);// 1000復(fù)制代碼
leta =100;leta =1000;// 報(bào)重復(fù)聲明錯(cuò)誤復(fù)制代碼
5. ES6聲明的變量不會(huì)掛在頂層對(duì)象
嗯~ES6變量的聲明是指哪些聲明呢?
指let, const, import, class聲明。
而var, function聲明是ES6之前的。
所以目前JavaScript有六種聲明變量的方式了~
varjob ='teacher';console.log(window.job);// teacher復(fù)制代碼
letjob ='teacher';console.log(window.job);// undefined復(fù)制代碼
const命令注意點(diǎn)
let可以先聲明稍后賦值;而const聲明之后必須立馬賦值,否則會(huì)報(bào)錯(cuò)
leta;a =100;// this is ok復(fù)制代碼
const a; // 報(bào)沒(méi)初始化數(shù)據(jù)的錯(cuò)誤復(fù)制代碼
const聲明了簡(jiǎn)單的數(shù)據(jù)類(lèi)型就不能更改了;聲明了引用類(lèi)型(數(shù)組,對(duì)象等),指針指向的地址不能更改,但是內(nèi)部的數(shù)據(jù)可以更改的
conststr ='this is a string';str ='this is another string';// 報(bào)了個(gè)“給不變的變量分配值”的錯(cuò)誤復(fù)制代碼
constobj = {name:'jia'}obj.name ='ming';// this is okobj = {};// 報(bào)了個(gè)“給不變的變量分配值”的錯(cuò)誤復(fù)制代碼
let和const的使用場(chǎng)景
let使用場(chǎng)景:變量,用以代替var
const使用場(chǎng)景:常量、聲明匿名函數(shù)、箭頭函數(shù)的時(shí)候。
// 常量constPI =3.14;// 匿名函數(shù)constfn1 =function(){// do something}// 箭頭函數(shù)constfn2 =()=>{// do something}復(fù)制代碼
變量的解構(gòu)賦值
解構(gòu)可以理解就是一個(gè)作用:簡(jiǎn)化你變量賦值的操作。
數(shù)組場(chǎng)景
let[name, job] = ['jiaming','teacher'];console.log(name);// jiaming復(fù)制代碼
本質(zhì)上,這種寫(xiě)法屬于模式匹配,只要等號(hào)兩邊的模式相同(重點(diǎn)),左邊的變量就會(huì)被賦予對(duì)應(yīng)的值。再比如:
let[ , , third] = ["foo","bar","baz"];console.log(third);// "baz"let[head, body, ...tail] = [1,2,3,4,5];console.log(tail);// [3, 4, 5]復(fù)制代碼
也可以使用默認(rèn)值。但是默認(rèn)值生效的前提是:ES6內(nèi)部使用嚴(yán)格相等運(yùn)算符(===),判斷一個(gè)位置是否有值。所以,只有當(dāng)一個(gè)數(shù)組成員嚴(yán)格等于undefined,默認(rèn)值才會(huì)生效。
let[x, y ='b'] = ['a'];// x='a', y='b'let[z =1] = [undefined];console.log(z);// 1let[k =1] = [null];console.log(k);// null復(fù)制代碼
對(duì)象場(chǎng)景
conststate = {name:'jiaming',job:'teacher'};let{name,job} = state;// 上面的場(chǎng)景很熟悉吧console.log(job);// teacher復(fù)制代碼
上面的例子如果寫(xiě)具體的話(huà),是這樣的:
conststate = {name:'jiaming',job:'teacher'};let{name: name,// 第一個(gè)name是匹配模式,第二個(gè)name才是變量,兩者同名簡(jiǎn)化成一個(gè)即可job: job} = state;復(fù)制代碼
我們來(lái)改寫(xiě)下:
conststate = {name:'jiaming',job:'teacher'};let{name: job,job: name} = state;console.log(job);// jiaming復(fù)制代碼
對(duì)象也可以使用默認(rèn)值,但是前提是:對(duì)象的屬性值嚴(yán)格等于undefined。
如下:
var{x =3} = {x:undefined};console.log(x);// 3var{y =3} = {y:null};console.log(y);// null復(fù)制代碼
字符串場(chǎng)景
字符串之所以能夠被解構(gòu)賦值,是因?yàn)榇藭r(shí)字符串被轉(zhuǎn)換成了一個(gè)類(lèi)似數(shù)組的對(duì)象。
const[a, b, ...arr] ='hello';console.log(arr);// ["l", "l", "o"]復(fù)制代碼
let{length: len} ='hello';console.log(len);// 5復(fù)制代碼
數(shù)值和布爾值場(chǎng)景
解構(gòu)賦值時(shí),如果等號(hào)右邊是數(shù)值和布爾值,則會(huì)先轉(zhuǎn)換為對(duì)象(分別是基本包裝類(lèi)型Number和基本包裝類(lèi)型Boolean)。不過(guò)這種場(chǎng)景用得不多~
let{toString: s} =123;console.log(s);// function toString() { [native code] }console.log(s ===Number.prototype.toString);// true復(fù)制代碼
let{toString: s} =true;console.log(s ===Boolean.prototype.toString);// true復(fù)制代碼
解構(gòu)賦值的規(guī)則是,只要等號(hào)右邊的值不是對(duì)象或數(shù)組,就先將其轉(zhuǎn)為對(duì)象。由于undefined和null無(wú)法轉(zhuǎn)為對(duì)象,所以對(duì)它們進(jìn)行解構(gòu)賦值,都會(huì)報(bào)錯(cuò)。
兩種使用場(chǎng)景
1. 交換兩變量值
let[a, b] = ['reng','jia'];[a, b] = [b, a];console.log(b);// 'reng'復(fù)制代碼
2. 將字符串轉(zhuǎn)換為數(shù)組
let[...arr] ='reng';console.log(arr);// ["r", "e", "n", "g"]console.log(arr.splice(0,2));// ["r", "e"] 返回刪除的數(shù)組(能使用數(shù)組的方法了)復(fù)制代碼
字符串?dāng)U展
針對(duì)字符串?dāng)U展這個(gè),個(gè)人感覺(jué)模版字符串使用的頻率比較高。模版字符串解放了拼接字符串帶來(lái)的繁瑣操作的體力勞動(dòng)。
letname ='jiaming';letstr ='Hello! My name is '+ name +'. Nice to meet you!';letstrTemp =`Hello! My name is${ name }. Nice to meet you!`復(fù)制代碼
對(duì)于新增的字符串方法,可以記下下面這幾個(gè):
includes(): 返回布爾值,表示是否找到了參數(shù)字符串
startWith(): 返回布爾值,表示參數(shù)字符串是否在原字符串的頭部
endWith(): 返回布爾值,表示參數(shù)字符串是否在原字符串的尾部
trimStart(): 返回字符串,表示消除參數(shù)字符串開(kāi)頭的空格
trimEnd(): 返回字符串,表示消除參數(shù)字符串結(jié)尾的空格
數(shù)值擴(kuò)展
留意下在Number對(duì)象上提供的新方法:
Number.isFinite(): 返回布爾值,表示參數(shù)值是否有限的
Number.isNaN(): 返回布爾值,用來(lái)檢查一個(gè)值是否為NaN
Number.isNaN(NaN)// trueNumber.isNaN(15)// false復(fù)制代碼
Number.isInteger(): 返回布爾值,用來(lái)判斷一個(gè)數(shù)值是否為整數(shù)
關(guān)于Math對(duì)象上的方法,遇到要用到時(shí)候,查API吧,不然記太多,腦瓜子會(huì)疼~
函數(shù)擴(kuò)展
rest參數(shù)
ES6引入rest參數(shù)(形式是...變量名),用于獲取多余的參數(shù),這樣就不需要使用arguments對(duì)象了。rest參數(shù)搭配的變量是一個(gè)數(shù)組(arguments是一個(gè)類(lèi)數(shù)組來(lái)的),該變量將多余的參數(shù)放入數(shù)組中。
arguments對(duì)象是一個(gè)類(lèi)數(shù)組,還得通過(guò)Array.prototype.slice.call(arguments)將其轉(zhuǎn)換為真數(shù)組;而rest參數(shù)直接就可以使用數(shù)組的方法了。
functionadd(...arr){console.log(arr);// [2, 5, 3]letsum =0;for(varvalofarr) {sum += val;}returnsum;}console.log(add(2,5,3));// 10復(fù)制代碼
箭頭函數(shù)
ES6允許使用“箭頭”(=>)定義函數(shù)。
constf =v=>v;// 注意是有返回值return的啊// 等同于constf =function(v){returnv;}復(fù)制代碼
如果箭頭函數(shù)的代碼塊部分多于一條語(yǔ)句,就要使用大括號(hào)將它們括起來(lái),并且使用return語(yǔ)句返回結(jié)果。
constsum =(num1, num2) =>num1 + num2;// 等價(jià)于,使用了大括號(hào),那箭頭函數(shù)里面就要使用return了constsum =(num1, num2) =>{returnnum1 + num2 }// 等價(jià)于constsum =function(num1, num2){returnnum1 + num2}復(fù)制代碼
使用箭頭函數(shù)注意點(diǎn):
函數(shù)體內(nèi)的this對(duì)象,就是定義所在的對(duì)象,而不是使用時(shí)所在的對(duì)象。
不可以當(dāng)作構(gòu)造函數(shù),也就是說(shuō),不可以使用new命令,否則會(huì)拋出一個(gè)錯(cuò)誤。
不可以使用arguments對(duì)象,該對(duì)象在函數(shù)體內(nèi)不存在的,如果要用,可以用rest參數(shù)代替。
不可以使用yield命令,因此箭頭函數(shù)不能用作Generator函數(shù)。
functionfoo(){setTimeout(()=>{console.log('id:',this.id);// id: 42},100);}varid =21;foo.call({id:42});復(fù)制代碼
// 錯(cuò)誤使用箭頭函數(shù)的例子constcat = {lives:9,jumps:()=>{// 箭頭函數(shù)的錯(cuò)誤使用,因?yàn)閷?duì)象不構(gòu)成單獨(dú)的作用域this.lives--;// this 指向window}}varbutton =document.getElementById('press');// 一個(gè)節(jié)點(diǎn)對(duì)象button.addEventListener('click', () => {// 箭頭函數(shù)的this指向windowthis.classList.toggle('on');});// 箭頭函數(shù)改成`function`匿名函數(shù)指向就正確了。復(fù)制代碼
箭頭函數(shù)適合處理簡(jiǎn)單的計(jì)算,如果有復(fù)雜的函數(shù)體或讀寫(xiě)操縱不建議使用,這樣可以提高代碼的可讀性。
關(guān)于尾遞歸和其優(yōu)化可以直接看阮先生的文檔
找下茬
假設(shè)有這么一個(gè)需求,需要對(duì)二維數(shù)組的元素進(jìn)行反轉(zhuǎn)并被1減。我們來(lái)看下下面代碼,哪個(gè)能實(shí)現(xiàn)此需求呢?
// 代碼一constA = [[0,1,1],[1,0,1],[0,0,0]];constflipAndInvertArr =function(A){? ? A.map(item=>{? ? ? ? item.reverse().map(r=>1-r)? ? })}復(fù)制代碼
// 代碼二constA = [[0,1,1],[1,0,1],[0,0,0]];constflipAndInvertArr =A=>A.map(res=>res.reverse().map(r=>1- r));復(fù)制代碼
運(yùn)行之后,發(fā)現(xiàn)代碼二是能實(shí)現(xiàn)需求的:
letresultArr = flipAndInvertArr(A);console.log(resultArr);// [[0, 0, 1], [0, 1, 0], [1, 1, 1]]復(fù)制代碼
嗯~上面已經(jīng)提到過(guò),箭頭函數(shù)體加上大括號(hào)后,是需要自己手動(dòng)return的~
我們來(lái)改寫(xiě)下代碼一,以便符合需求:
constA = [[0,1,1],[1,0,1],[0,0,0]];constflipAndInvertArr =function(A){return(A.map(item=>{returnitem.reverse().map(r=>1-r)? ? }))}letresult = flipAndInvertArr(A);console.log(result);// [[0, 0, 1], [0, 1, 0], [1, 1, 1]]
轉(zhuǎn)載自:
作者:call_me_R
鏈接:https://juejin.im/post/5d28422be51d457756536829