1.函數參數的默認值
ES6容許爲函數的參數設置默認值,即直接寫在參數定義的後面。編程
function log(x, y = 'World') { console.log(x, y); } log('Hello') // Hello World log('Hello', 'China') // Hello China log('Hello', '') // Hello
使用參數默認值時,函數不能有同名參數。
另外,一個容易忽略的地方是,參數默認值不是傳值的,而是每次都從新計算默認值表達式的值。也就是說,參數默認值是惰性求值的。數組
與解構賦值默認值結合使用
參數默認值能夠與解構賦值的默認值,結合起來使用。函數式編程
function foo({x, y = 5}) { console.log(x, y); } foo({}) // undefined 5 foo({x: 1}) // 1 5 foo({x: 1, y: 2}) // 1 2 foo() // TypeError: Cannot read property 'x' of undefined
函數的length屬性(函數預期傳入參數的個數)
指定了默認值之後,函數的length屬性,將返回沒有指定默認值的參數個數。也就是說,指定了默認值後,length屬性將失真。函數
做用域
一旦設置了參數的默認值,函數進行聲明初始化時,參數會造成一個單獨的做用域(context)。等到初始化結束,這個做用域就會消失。this
2.rest參數
ES6引入rest參數(形式爲…變量名),用於獲取函數的多餘參數,這樣就不須要使用arguments對象了。rest參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。prototype
function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(2, 5, 3) // 10 // arguments變量的寫法 function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); } // rest參數的寫法 const sortNumbers = (...numbers) => numbers.sort();
注意,rest參數以後不能再有其餘參數(即只能是最後一個參數),不然會報錯。
函數的length屬性,不包括rest參數rest
4.name屬性
函數的name屬性,返回該函數的函數名。
function構造函數返回的函數實例,name屬性的值爲anonymous。
bind返回的函數,name屬性值會加上bound前綴。code
5.箭頭函數
若是箭頭函數不須要參數或須要多個參數,就使用一個圓括號表明參數部分。
若是箭頭函數的代碼塊部分多於一條語句,就要使用大括號
將它們括起來,而且使用return語句返回。
var sum = (num1, num2) => { return num1 + num2; }對象
因爲大括號被解釋爲代碼塊,因此若是箭頭函數直接返回一個對象,必須在對象外面加上括號,不然會報錯。遞歸
// 報錯 let getTempItem = id => { id: id, name: "Temp" }; // 不報錯 let getTempItem = id => ({ id: id, name: "Temp" });
箭頭函數與rest參數結合的例子
const numbers = (...nums) => nums; numbers(1, 2, 3, 4, 5) // [1,2,3,4,5] const headAndTail = (head, ...tail) => [head, tail]; headAndTail(1, 2, 3, 4, 5) // [1,[2,3,4,5]]
箭頭函數有幾個使用注意點。
(1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
(2)不能夠當作構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。
(3)不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用rest參數代替。
(4)不可使用yield命令,所以箭頭函數不能用做Generator函數。
this指向的固定化,並非由於箭頭函數內部有綁定this的機制,實際緣由是箭頭函數根本沒有本身的this,致使內部的this就是外層代碼塊的this。正是由於它沒有this,因此也就不能用做構造函數。
6.尾調用
尾調用(tail call)是函數式編程的一個重要概念,自己很是簡單,一句話就能說清楚,就是指某個函數的最後一步是調用另外一個函數。
尾調用之因此與其餘調用不一樣,就在於它的特殊的調用位置。
咱們知道,函數調用會在內存造成一個「調用記錄」,又稱「調用幀」(call frame),保存調用位置和內部變量等信息。若是在函數A的內部調用函數B,那麼在A的調用幀上芳,就造成一個B的調用幀。等到B運行結束,將結果返回到A,B的調用幀纔會消失。若是函數B內部還調用函數C,那就還有一個C的調用幀,以此類推。全部的調用幀,就造成一個「調用棧」(call stack)。
尾調用因爲是函數的最後一步操做,因此不須要保留外層函數的調用幀,由於調用位置、內部局部變量等信息都不會再用到了,只要直接用內層函數的調用幀,取代外層函數的調用幀就能夠了。
函數調用自身,稱爲遞歸。若是尾調用自身,就稱爲尾遞歸。遞歸很是耗費內存,由於須要同時保存成千上百個調用幀,很容易發生「棧溢出」(stack overflow)。但對於尾遞歸來講,因爲只存在一個調用幀,多以永遠不會發生「棧溢出」錯誤。