90% 前端都會的 ES6 簡化代碼技巧,你用過哪些?


90% 前端都會的 ES6 簡化代碼技巧,你用過哪些?

本文主要講解一下內容:
  • 塊級作用域
  • 解構
  • 箭頭函數
  • 模板字符串
  • 剩余參數 / 展開語法
  • 對象字面量簡寫語法
  • 數組實例的 includes()
  • Async / await 異步語法

塊級作用域

為什么需要塊級作用域?

ES5只有全局作用域和函數作用域,沒有塊級作用域,這導致很多場景不合理。

 

  • 第一種場景,內層變量可能會覆蓋外層變量。

以上代碼的原意是,if代碼塊外部使用外層的 tmp 變量,內部使用內部的 tmp 變量。但是,函數 fn 執行后,輸出的結果為 undefined,原因在於變量提升導致內層的 tmp 變量覆蓋了外層的 tmp 變量。

 

 

  • 第二種場景,用來計數的循環變量泄露為全局變量。

上面代碼中,變量 i 只是用來控制循環,但是循環結束后,他並沒有消失,而是泄露成了全局變量。

 

let 實際上為 JavaScript 新增了塊級作用域。

上面的函數有兩個代碼塊,都聲明了變量 n ,運行后輸出 5 。這表示外層代碼塊不受內層代碼塊的影響。如果使用 var 定義變量,最后輸出的值就是 10。

那么我們能利用 塊級作用域 做什么呢?
我們先來做到面試題
看到這,相信聰明的你已經理解塊級作用域的好處了 O(∩_∩)O
那么 ES5 能不能實現 塊級作用域的效果呢?可以的,我們可以利用閉包

結構

解構:是將一個數據結構分解為更小的部分的過程。ES6中,從數組和對象中提取值,對變量進行賦值。

那么結構有什么用處呢?
1.可以大大的簡化變量的聲明操作。
// ES5
var foo = 1
var bar = 2
var baz = 3
// ES6
let [foo,bar,baz] = [1,2,3]
2.變量交換:看起來如同鏡像。賦值語句的左側的解構模式,右側是臨時創建的數組字面量。x 被賦值為數組中的 y,y 被賦值為數組中的x。
let x = 1
let y = 2
[x,y] = [y,x]
// x = 2, y = 1
3.對象結構
var obj = { x:1,y:2,c:1 }
let { x,y } = obj
// x = 1
// y = 2
4.字符串解構
const [a,b,c,d,e] = hello
// a => h
// b => e
// c => l
// d => l
// e => o
5.函數參數解構
const shaochang = {name:'少昌',age:18}
function getAge({ name,age }){ return `${name}今年${age}歲` }
getAge(shaochang) // 少昌今年18歲

箭頭函數

ES6 允許使用箭頭 => 定義的函數

var f = v => v
// 等同於ES5的
var f = function(v){ return v }

如果箭頭函數不需要參數或需要多個參數,就使用圓括號代表參數部分。

var f = () => 5
// 等同於 ES5 的
var f = function (){ return 5 }
var sum = (num1,num2) => num1 + num2
// 等同於 ES5 的
var sum = function(num1, num2){ return num1 +num2 }

箭頭函數可以與解構結合使用。

const full = ({ first, last }) => first + + last;
// 等同於 ES5 的
function full(person){ return person.first + + person.last; }

箭頭函數表達簡潔。

const isEven = n => n % 2 === 0
const square = n => n * n
var result = values.sort((a, b) => a - b)
// 等同於 ES5 的
var result = values.sort(function (a, b) { return a - b })

以上代碼只用了兩行,就定義了兩個簡單的工具函數。如果不用箭頭函數,可能就要占用多行,而且還不如現在這樣寫醒目。

箭頭函數使用注意點。
1.函數體內的 this 對象,就是定義時所在的對象,而不是使用時所在的對象。
2.不可以當做構造函數,也就是不可以使用 new 命令,否則會拋出一個錯誤。
3.不可以使用 arguments 對象,該對象在函數體內不存在。如果要用,可以使用 rest 參數代替。
4.不可以使用 yield 命令,因此箭頭函數不能作 Generator 函數。

上面四點中,第一點尤其值得注意。this 對象的指向是可變的,但是在箭頭函數中,它是固定的。
// ES6
function foo() { setTimeout(() => { console.log(id:,this.id) },100) }
// 轉換成 ES5
function foo(){ var _this = this; setTimeout(function () { console.log( id:,_this.id ) },100) }

上面代碼中,轉換后的 ES5 版本清楚地說明了,箭頭函數里面根本沒有自己的 this,而是引用外層的 this。

模板字符串

模板字符串(template string)是增強版的字符串,用反引號(``)標識。它可以當作普通字符串,也可以用來定義多行字符串,或者在字符串中嵌入變量。
const { log } = console
const name = wenshaochang
const age = 18
// 普通字符串拼接
const result = name + '今年' + age + '歲'
// 使用模板字符串
const result2 = `${name}今年${age}歲`
log(result) // wenshaochang今年18歲
log(result2) // wenshaochang今年18歲
// ${} 大括號可以放入任意的 JavaScript 表達式,可以進行運算
const result3 = `${name}今年${age * 2}歲`
log(result3) // wenshaochang今年36歲

剩余參數 / 展開語法

ES6 引入了 rest參數(形式為 ...變量名),用於獲取函數的多余參數,這樣就不需要使用 arguments 對象了。rest 參數搭配的變量是一個數組,該變量將多余的參數放入其中。
function sortNumbers(){ return Array.prototype.slice.call(arguments).sort() }
// 使用 rest
const sortNumbers = (...numbers) => numbers.sort()
比較以上兩種寫法可以發現,rest 參數的寫法更自然也更簡潔。
擴展運算符(spread)是三個點(...)如同 rest 參數的逆運算 將一個數組轉為用逗號分隔的參數序列
console.log(...[1, 2, 3]) // 1 2 3
console.log(1,...[2,3,4],5) // 1 2 3 4 5
下面是擴展運算符取代 apply 方法的一個實際例子,應用 Math.max 方法簡化求出數組中的最大元素。
// ES5 的寫法
Math.max.apply(null,[14,2,77])
// ES6 的寫法
Math.max(...[14,3,77])
// 等同於
Math.max(14,3,77)
擴展運算符提供了數組合並的新寫法。
// ES5
[1,2].concat(more)
// ES6
[1,2,...more]
對象的擴展運算符(...)用於取出參數對象的所有可遍歷屬性,拷貝到當前對象之中。
let z = { a:3, b:bb }
let n = { ...z }
n // { a:3, b:bb }
n === z // false
特別注意:... 擴展對象,只能做到當對象屬性是 基本數據才是深拷貝,如果是 引入數據類型,那就是淺拷貝。
let z = { a: 3, b: bb , c: { name: ccc } }
let n = { ...z }
n // { a: 3, b: bb , c: { name: ccc } }
n === z // false
n.c === z.c // true
// n.c 跟 z.c 是同一個引用地址

對象字面量簡寫語法

const name = wen
// ES5 寫法 const obj = { name:name, f:function(){ console.log(this.name) }, }
// ES6 簡寫 const obj2 = { name, f(){ console.log(this.name) } }
obj.f() // wen obj2.f() // wen

數組實例的 includes()

Array.prototype.includes 方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes方法類似。ES2016引入了方法。
[1,2,3].includes(2) // true
[1,2,3].includes(4) // false
[1,2,NaN].includes(NaN) // true
沒有該方法之前,我們通常使用數組的 indexOf 方法,檢查是否包含某個值。
// ES5 if (arr.indexOf(el) !== -1) { // ... }
// ES6 if (arr.includes(el)) { // ... }
// 那么 indexOf 能不能做到類似於 includes 的寫法呢? 我們可以利用 ~ 位運算符 if (~arr.indexOf(el)) { // ... }
indexOf 方法有兩個缺點,一是不夠語義化,它的含義是找到參數值的第一個出現位置,所以要去比較是否不等於-1,表達起來不夠直觀。二是,它內部使用嚴格相等運算符(===)進行判斷,這會導致對 NaN 的誤判。
;[NaN].indexOf(NaN) // -1
includes 使用的是不一樣的判斷算法,就沒有這個問題
;[NaN].includes(NaN) // true

Async / await 異步語法

ES2017 標准引入了 async 函數,使得異步操作變得更加方便。
async 函數是什么?一句話,它就是 Generator 函數的語法糖。
async function getTitle(url) { let response = await fetch(url) let html = await response.text() return html.match(/([sS]+)/i)[1] }
getTitle( https://tc39.github.io/ecma262/ ).then((res) => console.log(res))
上面代碼中,函數 getTitle 內部有三個操作:抓取網頁、取出文本、匹配頁面標題。只有這三個操作全部完成,才會執行 then 方法里面的 console.log

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM