第三章 函數數組
函數形參的默認值閉包
ES5模擬默認參數app
function makeRequest (url, timeout, callback) { timeout = timeout || 2000; callback = callback || function () {}; }
爲形參賦予默認值,說明了該參數爲可選參數。函數
ES6的默認參數值優化
function makeRequest (url, timeout = 2000, callback = function () {}){ // 函數執行 }
須要注意的是,在參數中,null也是合法的參數值,因此傳入null的時候不會用默認值替代。this
ES6真正的可選參數是參數後面帶?聲明。url
默認參數值對arguments對象的影響rest
在ES5非嚴格模式中,函數命名參數的變化會體如今arguments對象中。code
在ES5嚴格模式中,不管參數如何變化,arguments對象再也不隨之改變。對象
ES6默認處於嚴格模式,默認參數值的存在使得arguments對象保持與命名參數的分離。
默認參數表達式
默認參數值能夠使用任意數據類型,甚至是函數執行返回的結果。
ES6的參數聲明具備臨時性死區的特性,不能在聲明以前調用。
function add (first = second, second = 1) { return first + second; } // 這是一個運行時纔會拋出的錯誤,只有當first傳入了非法值,引起默認值賦值的時候,纔會拋出error。 add(1, 2); //3,沒有使用默認值 add(); // ReferenceError,使用默認值時候發如今second聲明前使用了second
處理無命名參數
ES5中的無命名參數
ES5調用arguments對象來獲取全部的實參,從而間接地對無命名參數操做。
不定參數
ES6引入在命名參數前的三個點...來代表不定參數(rest parameters)。全部自它以後傳入的全部參數,都被歸入以這個參數命名的數組中。ES6中arguments依然存在,可是應當儘量地使用不定參數來替代它的做用。
使用限制:
加強的Function構造函數
ES6加強了Function構造函數的功能,支持在建立函數時定義默認參數和不定參數。
var add = new Function('first', 'second = 1', 'return first + second;'); add(1, 1); // 2 add(1); // 2
name屬性
ES6爲全部函數添加了name屬性,其特性爲:
不能使用name來獲取對於函數的引用。
展開運算符
和不定參數使用相對的是展開運算符,一樣也是...聲明。
它使用在傳遞實參的時候,將一個Array展開爲參數表的形式。
let values = [25, 50, 75, 100]; // 二者等價 Math.max.apply(Math, values); Math.max(...values);
明確函數的多重用途
JS函數有兩個不一樣的內部方法: [[Call]]和[[Construct]]。
經過new關鍵字調用函數時,執行的是[[Construct]]函數,它負責建立一個實例對象,而後再執行函數體,將this綁定到實例上。
不經過new調用函數,則執行[[Call]]函數,直接執行代碼中的函數體。
ES5判斷函數被調用方法
使用this instanceof class的形式。
function Person (name) { // new關鍵字將this綁定到實例 if(this instanceof Person) { this.name = name; } // [[Call]]調用不會綁定this到實例 else { throw new Error('必須使用new關鍵字調用Person'); } }
元屬性(Metaproperty)new.target
new.target表示new操做符的目標,即該構造函數。若是[[Call]]方式調用,則其爲undefined。
塊級函數
ES6引入塊級做用域後,在塊級做用域中聲明的函數只能在塊內使用,當跳出塊後,該函數將沒法訪問。
嚴格模式下,function聲明的塊級函數會被提高到塊級做用域的頂部。
非嚴格模式下,function聲明的跨級函數會被提高到外層的函數做用域。
箭頭函數(Lambda)
與傳統函數的不一樣:
lambda表達式也有name屬性,相似於函數。
沒有this綁定
lambda表達式的this必須經過查找做用域鏈來決定其值。
箭頭函數的返回值
沒有用{}包裹時,lambda表達式只能有一條執行語句,並返回該語句的返回值。
var result = [].sort((a, b) => a - b); // 等同於 return a - b
尾遞歸優化(TCO)
function TCO (fn) { let value, active = false, accumulated = []; // 在f內部進行遞歸調用的時候,其實調用的是這個返回的accumulator // 這裏須要注意的是,要將f中的遞歸調用函數名使用accumulator被賦予的變量名 return function accumulator(...args){ accumulated.push(args); if(!active) { active = true; while(accumulated.length) { /** * 因爲每次須要遞歸的fn.apply都會致使accumulated被push進一個新的arguments, * 因此這個while一直要到所有執行結束纔會跳出, * 但這種結構只會保持最多兩層的調用棧 */ value = fn.apply(this, accumulated.shift()); } active = false; return value; } } } var sum = TCO(function(x, y) { if(y > 0) { // 再次調用的實際上是閉包返回的accumulator,而不是這個傳入的function return sum(x + 1, y - 1); } else { return x; } });