// 普通遞歸函數的調用 時間複雜度爲 O(n)javascript
function fn(num){
if(num === 1) return 1;
return num * fn (num -1);
}
// 等同於 該函數耦合性更小
function fn(num){
if(num === 1) return 1;
return num * arguments.callee(num - 1);
}java
console.log(fn(50)) // 120es6
// 尾調用函數 優化了遞歸調用 事件複雜度爲O(1)
function ofn (num, sum){
if(num === 1) return sum;
return ofn(num - 1, num * sum);
}
console.log(ofn(5, 1)); // 120瀏覽器
// 固然爲了優化尾調用函數,咱們能夠多加一個函數調用的步驟
function ofn1(num){
return ofn(num, 1);
}
console.log(ofn1(5)); // 120app
得出的結果都是同樣的,這樣優化了前面函數的調用參數值不直觀的優化。
不太明白的夥伴們會問,爲何遞歸調用還須要傳入第二個參數,因此ofn1函數就是對上一個函數的優化。
這樣咱們就能夠遞歸調用傳入一個參數從而獲得遞歸後的值!wordpress
固然了,看了《javascript高級程序設計(第三版)》這一本書中有講到「柯里化」的概念,函數
它的主要的優勢就是:1.參數複用,2.加載一次屢次運行,3.延遲運行,等性能
例如:
柯里化函數參數轉換:
var currying = function(fn) {
// 從第二個傳入的參數開始截取,隔離第一個參數
var args1 = [].slice.call(arguments, 1);
// 返回一個函數(此處的函數爲一個內部函數)外部調用的時候,只是會以函數表達式的形式展示出來
return function() {
var args2 = args1.concat([].slice.call(arguments));
return fn.apply(null, args2);
};
};
/* 註釋 */
// alert(currying) // 指的是當前整個函數currying
// alert(currying()) // 指的是內部返回的匿名函數 function(){}優化
// "被代理函數"
function proxied ([ ... options ]) {// do something...}this
// 在此出我把這一層理解爲「代理層(對函數默認參數的傳定)」(若有理解誤區,望大牛指點)
var proxy = currying (proxied, [ ... ]); // 參數傳入 默認傳參項,
// 最終只須要調用代理函數傳入部分,或則最終的參數
proxy([ ... ]);
返回函數的優勢:在程序第一次執行的時候,就把返回的函數給肯定,當再次加載該函數的時候,
就不須要再次去判斷什麼的,直接到內存中抓取並使用。這樣作的目的主要是優化性能。(在此處可能並無獲得多大的體現)
可是在此處返回一個帶參數的函數,中間就多出來一層函數的調用,中間層就能夠作「代理」的用途了
言歸正傳:
咱們的例如就是將多個參數化爲一個參數的形式就行傳參,將其餘的參數在另外一個域中進行初始化了!
正真的例如來了:
// 按照柯里化的概念設計一個柯里化函數。
// 函數表達式一:①
function currying (func) {
var args1 = [].slice.call(arguments, 1);
return function() {
var args2 = args.concat([].slice.call(arguments));
/*
* 將傳入進來的參數進行倒敘,可是有個問題,
* 在柯里化的函數裏最好不要修改原型 能夠從下面調用的函數進行想辦法
*/
// return func.apply(null, args2.reverse());
return func.apply(null, args2); // 保留原型
};
};
/**函數表達式二:②
* 原本打算這種形式進行尾處理優化,由於更具柯里化currying函數的規則,
* 咱們須要把函數的參數的位置進行更改一下(該函數不能與上面柯里化函數並用,須要調用下面一個更改後的函數)
*/
function ofn (num, sum){
if(num === 1) return sum;
return ofn(num - 1, num * sum);
}
/**函數表達式三:③
* 修改以後的函數表達式,
*/
function ofn(sum, num) {
if (num === 1) return sum;
return ofn(num * sum, num - 1);
}
// 函數表達式三:④
// 調用currying函數,進行傳入默認的參數
var final = currying(ofn, 1);
// 函數表達式三:⑤
// 最終調用的形式
final(5); // 120
組合表達式:①+③+④+⑤
或利用簡單一點的柯里化表達式:
// 函數表達式三:⑥
function currying (proxyFn, second){
return function (another) {
return proxyFn.call(this, another, second);
}
}
組合:⑥+②+④+⑤
固然了還有更簡單的方法來實現,就是ECMAScript6標準,部分瀏覽器實現了一些ES6的特性
function recu (num, sum = 1) {
if (num === 1) {
return sum;
}
return recu (num - 1, num * sum);
}
函數調用: recu (5) // 120
參考資料: