顧名思義 用箭頭 “ => ” 定義函數,如果箭頭函數的代碼塊部分有多條語句,就要使用大括弧將它們括起來,並且使用return返回。由於花括弧{ }被解釋為代碼塊,所以如果箭頭函數直接返回一個對象,必須在對象外面加上花括弧,否則會報錯。 ...
項目開發中一些常用的es6知識,主要是為以後分享小程式開發、node+koa項目開發以及vueSSR(vue服務端渲染)做個前置鋪墊。
項目開發常用es6介紹
-
1、塊級作用域 let const
-
2、箭頭函數及this指向
-
3、promise、
- 4、async await語法
-
4、模塊化 module export和import
-
5、解構賦值、字元串模板
-
……
箭頭函數
顧名思義 用箭頭 “ => ” 定義函數
//es5的函數 var fn = function(num) { return num; } //用箭頭函數就可以這樣寫 var fn = num => num //沒有參數可以這麼寫 var fn = () => 1 //參數多的時候可以這樣寫 var fn = (num, num1, num2) => num
如果箭頭函數的代碼塊部分有多條語句,就要使用大括弧將它們括起來,並且使用return返回。
var func = (a, b) = > { ... //此處省略多行 return b; }
由於花括弧{ }被解釋為代碼塊,所以如果箭頭函數直接返回一個對象,必須在對象外面加上花括弧,否則會報錯。
var func = (a, b) => { name: a, age: b } //報錯 var func = (a, b) => { { name: a, age: b } } //不報錯
所以由上述示例可以看出箭頭函數的一個作用是簡化代碼。
箭頭函數還有一個更主要的作用:解決this的指向問題
this指向
先說一下普通函數中的this,普通函數中的this表示調用此函數時的對象。而箭頭函數是沒有自己的this的,箭頭函數裡面的this會繼承自外部的this。或者用代碼塊的概念解釋會更加直觀:箭頭函數中的this就是外層代碼塊的this。舉一個例子:
var x = 11; var obj = { x: 22, methods: { x: 33, say: function() { console.log(this.x) }, say2: () => { console.log(this.x) } } } obj.methods.say();//33 普通函數this表示調用次函數時的對象即methods對象 obj.methods.say2();//11 say2中this所在的外層代碼塊(向外數一個花括弧)是methods對象 但並不是說this就是該對象,而是指methods對象中的this 此時this是window
再看一個例子:
var btn = document.getElementById('btn'); btn.onclick = function() { setTimeout(function() { console.log(this) //普通函數中的this指的是window }, 100) setTimeout(() => { console.log(this) //箭頭函數中的this在定義的時候就已經綁定了,即繼承自this當前所在代碼塊的外層代碼塊中的this //而外層代碼塊是一個普通函數this自然就指向調用該函數時的對象(id為btn的button按鈕) }, 100) }
尾調用優化
首先來說一下什麼是尾調用:尾調用指某個函數的最後一步是調用另一個函數。
請小心這裡有一個深坑“最後一步”,舉幾個例子:
function f(x) { let y = g(x); return y }//不是尾調用,因為最後一步返回了y,不是調用函數 function f(x) { return g(x) + 1 }//不是尾調用,因為最後一步是加一,不是調用函數 function f(x) { g(x) }//不是尾調用,因為函數的最後一步是一個預設的return undefined; function f(x) { return g(x) }//是尾調用
很多同學會疑問,為什麼要做尾調用優化呢?這是一個事關記憶體優化的功能。
函數調用會在記憶體形成一個“調用記錄”,又稱“調用幀”。每形成一個調用幀就會占用一定的記憶體,假如有一個函數A裡面調用了函數B,函數B裡面又調用了函數C,以此類推。
在不是尾調用的情況下,因為js是單線程同步的,所以只有當函數B執行完畢才會執行函數A的return語句(函數沒寫return會有一個預設的return undefiend;),此時函數B的調用幀才會消失。但事實上,只有當函數B執行到return語句時才會執行完畢,而在函數B執行return之前會先調用函數C,所以當這種函數調用越來越多的時候,形成的調用幀也會越來越多占用的記憶體就會越來越大。俗話說精滿自溢,記憶體也會有溢出的時候是吧,這就不行了!所以要用尾調用!
尾調用由於是函數的最後一步操作,所以不需要保留外層函數的調用幀,只要直接用內層函數的調用幀,取代外層函數的調用幀就可以了。
比如在執行遞歸的時候就可以利用尾調用達到優化記憶體的目的。函數調用自身,稱為遞歸。如果尾調用自身,就稱為尾遞歸。
遞歸非常耗費記憶體,因為需要同時保存成千上百個調用幀,很容易發生“棧溢出”。但對於尾遞歸來說,由於只存在一個調用幀,所以永遠不會發生“棧溢出”錯誤。
//遞歸 計算n的階乘,最多需要保存n個調用記錄,複雜度 O(n) function factorial(n) { if (n === 1) return 1; return n * factorial(n - 1) } factorial(5) //120 //改成尾遞歸,只保留一個調用記錄,複雜度 O(1) function factorial(n, total) { if (n === 1) return total; return factorial(n - 1, n * total) } factorial(5, 1) //120
歡迎掃描下方二維碼關註,這裡更多前端技術分享,讓我們一起成長 -- web前端周刊