回答:
私は一般的にネストされた関数、特にJavaScriptを好んでいます。
多くの反対派は、ほとんどのプログラマーがC / C ++ / Javaの伝統で育てられたか、他の誰かに教えられたという事実から来ていると思います。入れ子になった関数は、プログラミングを学んでいたときにあまり触れられなかったため、自然に見えません。それは、それらが役に立たないという意味ではありません。
いくつかの理由により、グローバルスコープに配置する必要があります。
ヘルパー関数を呼び出し元にネストすると、呼び出し元の長さが長くなります。関数の長さはほとんどの場合負の指標です。短い関数は理解しやすく、記憶しやすく、デバッグや保守が簡単です。
ヘルパー関数に意味のある名前がある場合は、近くの定義を見る必要なく、その名前を読むだけで十分です。あなたがいる場合行う、呼び出し元の機能を理解するために、ヘルパー定義を参照する必要性を、その呼び出し側はあまりやっている、または同時に抽象化のあまりに多くのレベルに取り組んでいます。
ヘルパーをグローバルに使用可能にすると、他の関数が一般的に有用になった場合にそれを呼び出すことができます。ヘルパーが利用できない場合、それをカットアンドペーストしたり、それを忘れて再実装したり、他の機能を必要以上に長くしたいと思うでしょう。
ヘルパー関数をネストすると、宣言せずに呼び出し元のスコープの変数を使用する誘惑が高まり、ヘルパーの入力と出力が不明になります。関数がどのデータをどのように処理し、どのような影響を与えるかを明確に述べていない場合、それは通常、責任が不明確であることを示しています。ヘルパー関数をスタンドアロン関数として宣言すると、実際に何をするのかを知る必要があります。
編集
それは、私が思っていたよりも議論の余地のある問題であることが判明しました。明確にするために:
JavaScriptでは、言語が他のスコープ制限メカニズムを提供しないため、大きなファイルスパン関数がクラスの役割を果たすことがよくあります。確かに、ヘルパー関数は、そのような準クラスの外側ではなく、内側にあるべきです。
また、再利用が簡単になるという点は、サブルーチンがより広く使用されるようになった場合、完全に適切な場所に移動して、適切な場所、たとえば文字列ユーティリティライブラリまたはグローバル構成レジストリに配置することを前提としています。そのようなコードを注文したくない場合は、より「ブロックの多い」言語で通常のメソッドオブジェクトを使用するのと同じように、サブルーチンをネストすることもできます。
クロージャー内に両方の機能を配置するために、3番目のパスを提案します。次のようになります。
var functionA = (function(){
function functionB() {
// do stuff...
}
function functionA() {
// do stuff...
functionB();
// do stuff...
}
return functionA;
})();
IIFEで両方の関数の宣言をラップすることにより、クロージャーを作成します。IIFEの戻り値はパブリック関数であり、関数の名前の変数に格納されます。パブリック関数は、グローバル関数として宣言された場合とまったく同じ方法で呼び出すことができますfunctionA()
。戻り値は関数の呼び出しではなく関数であるため、最後に括弧がないことに注意してください。
このように2つの関数をラップすることにより、functionB
完全にプライベートになり、クロージャの外部からアクセスすることはできませんが、のみに表示されfunctionA
ます。これは、グローバルな名前空間を乱雑にされていない、との定義を乱雑にされていませんfunctionA
。