1.函數的默認值
從ES6開始,允許為函數參數設置默認值,即直接寫在參數定義的后面。這樣做使代碼變得簡潔自然,另外還有兩個好處:
- 可以方便明確的知道哪些參數有默認值是可以省略的
- 有利於將來的代碼優化,即使去掉這個參數也不會導致以前的代碼無法運行
另外,參數變量是默認聲明的,因此不能再使用let和const命令再次聲明。定義了默認值的參數應該是函數的尾參數,這樣就可以很容易的看出到底省略了哪些參數。如果尾部參數沒有設置默認值那么是無法省略的。另外也無法直接省略處在中間的有默認值的參數,除非顯示傳入undefined
與解構賦值結合使用
function m1({x:0,y:0} = {}){ return [x, y]; } function m2({x,y} = {x:0,y:0}){ return[x, y]; } m1()//[0,0] m2();//[0,0] m1({x:3, y:8});//[3,8] m2({x:3,y:8});//[3,8] m1({x:3});//[3,0] m2({x:3});//[3, undefined]
length屬性
指定默認值以后函數的length屬性返回的是沒有指定默認值參數的個數,因為length屬性的含義就是函數預期傳入參數的個數,當某個參數指定了默認值以后預期的傳入參數就不再包括已經指定默認值的參數。
2.rest參數與擴展運算符
ES6引入rest參數(形式為’…變量名’),用於獲取函數的多余參數,該功能類似於Java中的不確定數量的參數,rest參數將不定個數的參數轉換為名稱為指定變量名的數組,然后我們可以通過眾多的數組函數對其進行操作
注意一點,rest函數必須是函數的最后一個參數否則會報錯
與rest參數相反,擴展運算符 … 將一個數組轉為用逗號分隔的參數序列。擴展運算符提供了眾多的用途
替代數組的apply方法
//ES5 Math.max.apply(null,[14,2,4]); //ES6 Math.max(...[14,2,4]);
合並數組
var arr1 = ['a', 'b']; var arr2 = ['c', 'd']; var arr3 = ['e']; //ES5 arr1.contact(arr2,arr3); //ES6 [...arr1, ...arr2, ...arr3];//['a', 'b', 'c', 'd', 'e']
與解構賦值結合
兩者可以結合使用生成數組
const [first, ...rest] = [1, 2, 3, 4, 5]; first //1 rest //[2,3,4,5]
將字符串轉為數組
[..."hello"]// ['h', 'e', 'l', 'l', '0']
轉換類似數組的對象、Set、Map以及Generator函數、
//轉換對象 var nodelist = document.querySelectorAll('div'); var array = [...nodelist] //轉換Map。Map和Set都是具有Iterator的對象, 只要是具有Iterator接口的對象都可以使用擴展運算符 let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]); let arr = [...map.keys()];//[1, 2, 3] //轉換Generator函數,Generator函數運行后返回一個遍歷器對象,因此也可以使用擴展運算符 var go = function*(){ yield 1; yield 2; yield 3; };
3.name屬性
函數的name屬性返回函數名,如果是匿名函數,ES5返回空字符串,而ES6返回實際的函數名。Function構造函數返回的函數示例name屬性值為’anonymous’,bind返回的函數name屬性值會加上’bound’前綴
var func1 = function(){}; func1.name;//ES5:"" ES6:func1 //如果將一個具名函數返回給一個變量,ES5/ES6都會返回這個具名函數原本的名字而不是變量名 const bar = function baz(){}; bar.name();//baz
4.箭頭函數
ES6允許使用* 箭頭 => *定義函數,箭頭左邊為參數,右邊為方法體。如果不需要參數則用圓括號代表參數部分,如果方法體多於一行則用大括號括起來並用return表示返回。
var f = v => v; //等價於 var f = function(v){ return v}; var f = ()=>5; //等價於 var f = function(){ return 5; }
箭頭函數的幾點注意:
* 函數體內的this總是該函數定義時所在的對象。因為箭頭函數根本沒有自己的this,因此其內部的this就是外層代碼塊的this
* 不可以當做構造函數,即不可以使用new命令
* 不可以使用arguments對象,該對象在函數體內不存在, 可以用rest代替
* 不可以使用yield命令,因此箭頭函數無法用作Generator函數
5.函數綁定、尾逗號以及尾調用優化
ES7提出了函數綁定用來取代call、apply、bind調用,運算符是雙冒號* :: *, 其坐標是一個對象,右邊是一個函數,它將自動將左邊的對象作為上下文環境(即this對象)綁定到右邊的函數中。其返回的還是原對象因此可以使用鏈式調用
尾調用優化
尾調用是函數式編程的一個重要概念, 指某個函數的最后一步是調用另一個函數。尾調用可以不出現在尾部,只要是函數操作的最后一步即可。
在函數的調用過程中,會形成調用棧,尾調用與其他的調用不同在於因為尾調用是函數的最后一步操作,因此不需要外層函數的調用棧,這樣就只保留了內層的調用棧。因此如果所有的函數都是尾調用那么完全可以做到每次執行調用時只有一幀,將大大的節省內存,這就是所謂的尾調用優化
尾調用可以對遞歸進行優化。函數調用自身成為遞歸,如果尾調用自身就成為尾遞歸。因為可能需要保存大量的調用棧因此非常消耗內存。尾遞歸很好的解決了這一問題。
尾遞歸的實現往往需要改寫遞歸函數,確保其最后只調用自身。方法就是:把所有用到的內部變量變為函數的參數。但這么做會導致函數的可讀性降低,這里有兩個方法解決:
一是在尾遞歸函數之外再提供一個正常形式的函數來調用尾遞歸函數,另一個就是柯里化,是函數式編程的一個概念,是將多參數的函數轉換為單參數的形式。
尾逗號
從ES6開始允許函數的最后一個參數有尾逗號
function func( foo, bar,){ }