es6允許為函式的引數設定預設值,即直接寫在引數定義的後面。
function
log(x,y=
'world'
)log
('hello'
)//hello world
log(
'hello'
,'yivi'
)//hello yivi
log(
'hello',''
)//hello
引數變數是預設宣告的,因此不能再用let或const再次宣告,也不能用同名的引數。
function
foo(x=5)
引數預設值可以與解構賦值的預設值結合使用。
function
foo(
)foo()
//undefined,5
foo(
)//error: cannot read property 'x' of undefined
foo(
)// 1,5
foo(
)//1,2
來看看下面兩種形式:
functionf1(
=)functionf2(
=)f1(
)//[0,0]f2(
)//[0,0]f1(
)//[3,undefined]f2(
)//[3,1]f1(
)//[undefined,undefined]f2(
)//[1,1]
如果定義了預設值的引數在函式的最尾部,則可以省略;如果非尾部的引數設定預設值,實際上這個引數無法省略,必須以undefined填充。
function
foo(x,y=
1,z)
foo();
//[undefined,1,undefined]
foo(1,
2,3)
//[1,2,3]
foo(1,
,2)//error
foo(
1,undefined,2)
//[1,1,2]
指定預設之後,函式的length方法將只返回沒有預設值的引數個數,也就是length將失真。這是因為length的本意是該函式預期傳入引數的個數。
(
function
(x,y,z=1)
).length =
2//引數個數為3,但返回2
一旦設定了預設值,函式宣告初始化的時候,引數就會形成乙個單獨的作用域,等到初始化結束,作用域就會失效。
var x=1;
function
foo(x,y=x)f(
2)//[2,2]
以上例子中,由於函式設定了預設值,在函式內部會形成單獨的作用域,因此函式中的y=x
中的x指的是引數的x,而不是全域性變數x。
es6引入了rest引數...rest
來獲取函式多餘的引數,這樣就無需引用arguments物件了。rest引數搭配的變數是乙個陣列,該變數將多餘的引數放入其中。
function
add(
...num)
return sum;
}add(1
,2,3
,4,5
)//15
注意:函式的length屬性並不包括rest 的引數個數
尾呼叫,顧名思義,就是指某個函式的最後一步是呼叫另乙個函式。
function
f(x)
//以下都不屬於尾呼叫
function
f(x)
function
f(x)
function
f(x)
尾呼叫的標誌是,必須是在最後呼叫函式,而不是操作呼叫後的結果。
我們知道,函式呼叫會在記憶體形成乙個「呼叫記錄」, 又稱「呼叫幀」(call frame),儲存呼叫位置和內部變數等資訊。如果在函式 a 的內部呼叫函式 b,那麼在 a 的呼叫幀上方還會形成一 個 b 的呼叫幀。等到 b 執行結束,將結果返回到 a, b 的呼叫幀才會消失。 如果函式 b 內部還呼叫函式 c,那就還有乙個 c 的呼叫幀,以此類推。所有的呼叫幀就形成乙個「呼叫棧」(call stack)。
尾呼叫由於是函式的最後一步操作,所以不需要保留外層函式的呼叫幀,因為呼叫位置、 內部變數等資訊都不會再用到了,直接用內層函式的呼叫幀取代外層函式的即可。
functionf(
)//等同於g(
3);
上面的**中,如果不是尾呼叫,函式f就需要儲存變數x,y的值、g的呼叫資訊等。但由於尾呼叫,函式f就結束了,所以記憶體中可以刪除f的呼叫記錄,只保留g的呼叫幀。這就是尾呼叫優化,可以大量節約記憶體。
遞迴是一種非常消耗記憶體的方法,因為其需要儲存大量的呼叫幀,容易發生記憶體溢位等錯誤,但尾遞迴就很好的解決了這個問題,因為他永遠只占用乙個呼叫幀。
// 階乘函式
function
factorial
(n)else
}// 我們尾遞迴真的太厲害了(老財富密碼了)
// 普通遞迴,不好用!尾遞迴,好用!
function
factorial
(n,total)
else
}//fibonacci數列
function
fibonacci
(n)else
}// 普通遞迴,不好用!尾遞迴,好用!
function
fibonacci
(n,ac =
1,ac =1)
else
}
上面的**似乎不是很合邏輯,為什麼我算乙個階乘還要傳乙個total進去呢,難道就不能直接給我結果嗎?答案是可以的。別忘了,es6給我們提供了預設值操作!
function
factorial
(n,total =1)
else
}factorial(5
)//120
還有一種尾呼叫的方法,就是在尾遞迴函式外再提供乙個正常形式的函式來進行尾遞迴:
function
tailfactorial
(n,total)
else
}function
factorial
(n)factorial(5
);//120
這其實是一種柯里化思維。等會兒!啥叫柯里化???
柯里化函式程式設計中有乙個重要的概念,叫做柯里化,意思是將多引數的函式轉化成單引數的形式。
function
curry
(fn,n)
//返回乙個可執行函式
}function
tailfactorial
(n,total)
else
}const factorial =
curry
(tailfactorial,1)
;factorial(5
)//120
es6的函式拓展
參考 1.增加函式預設值 es6允許為函式提供預設值,與解構賦值一起使用,非常地方便 function foo foo 相當於執行let 輸出undefined 5 foo 相當於執行let 輸出 1 5 foo 1 2 foo typeerror cannot read property x of...
ES6 函式的拓展 四
一 引數帶預設值函式 1 在函式形參可以賦予函式預設值 即實參嚴格匹配undefined時,在函式內部使用形參時呼叫它的預設值 2 函式name屬性 返回函式名稱,無名的函式返回空字串 3 函式length屬性 從左往右開始計算函式形參直到碰到帶有預設值形參時結束計算,這樣計算的形參個數 eg 普通...
es6 陣列拓展
陣列 屬性 constructor,length,prototype 方法 push,pop,shift,unshift 新增 splice,slice,reverse,sort,concat,filter,map,some,every 1 filter 過濾出符合條件的值,返回新陣列 var sp...