ES6系列之函數

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)。但對於尾遞歸來講,因爲只存在一個調用幀,多以永遠不會發生「棧溢出」錯誤。

相關文章
相關標籤/搜索