隣り合う歩を積まない拡散談JavaScriptの再帰関数

3018 ワード

最近はargments.caleeという属性を見て、JavaScriptの中の再帰がこんなに多くの穴があることを知りました.以前は分かりませんでしたが、今日は整理します.まず最初から始めましょう.
再帰的に1つの階乗関数を実現します.
ここでは定義はもちろん、直接コードを入れます.正常モードで.
function factorial(num){
    if(num<=1){
        return 1;
    }else{
        return num * factorial(num-1);
    }
}
上記は典型的な再帰的な呼び出しですが、問題があります.
var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4));//  
再帰関数とは、一つの関数で名前で自分を呼び出す場合です.正常な状況では大丈夫ですが、鍵はJavaScript言語と他の言語は違っています.関数名はポインタだけです.関数の実体オブジェクトではありません.だから、私たちはこの針を変えたら、関数の中の針を呼びつけるのは自分ではないです.上の例では、直接にそれを消します.空を指さしたら、まっすぐに崩れてしまいます.
ここで重要な属性を引き出しました.
argments.calleecalleeargumentsオブジェクトの属性であり、arguments.calleeは実行中の関数を指すポインタの値である.したがって、関数の再帰的呼び出しが可能になる.
たとえば:
function factorial(num){
    if(num<=1){
        return 1;
    }else{
        return num * arguments.callee(num-1);
    }
}
arguments.calleeプロキシ関数名を使用することにより、どのように関数を呼び出しても問題がないことを確認することができる.そのため、通常のモードでは、この方法を使うとより安全です.
しかし、厳密なモードでは、上記のarguments.calleeを呼び出しても、argumentsをサポートしていないので、エラーが発生します.どうすればいいですか?
厳格なモードではarguments.calleeは使えません.どうすればいいですか?
命名式を使うことでも同じ効果が得られます.コードを見る:
var factorial = (function f(num){
     if(num<=1){
        return 1;
    }else{
        return num * f(num-1);
    }
});
上記のコードはf()という名前付き表現を作成し、変数factorialに値を与えます.このように変数を別の変数に変えても、私の内部の呼び出しには影響しません.f関数名はまだ有効です.したがって、再帰関数呼び出しは正しく実行されます.ECMAのバージョンを6にアップグレードします.ES6の場合は?ES6の場合、私たちは別の方法で書き上げることができます.たとえば:
const factorial = (function f(num){
     if(num<=1){
        return 1;
    }else{
        return num * f(num-1);
    }
});
私たちはvarconstにアップグレードして、この変数を定数にします.このように変数も変えられません.上記のネーミング関数の代わりに矢印関数を使います.
const factorial =num=>{
     if(num<=1){
        return 1;
    }else{
        return num * factorial(num-1);
    }
}
定数は変更できませんので、上記のコードを作成することができます.コードは大丈夫だと思いますか?
私たちはこのように呼び出します.
factorial(100000);
次に以下のエラーを報告します.RangeError:最大呼び出しスタックサイズを超えました.
RangeError: Maximum call stack size exceeded
    at factorial (H:\company_work_space\Demos\Demo1.js:40:18)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
    at factorial (H:\company_work_space\Demos\Demo1.js:44:22)
次はどうやってこの問題を解決しますか?答えはテイルコールを使って最適化します.テールコールとは何ですか?まずこれを見てもいいです.終端コールとは何ですか?