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