web-dev-qa-db-ja.com

別の関数のみを呼び出すパラメーターなしの関数の利点は何ですか

私がやっているチュートリアル(Javascript用)は、次のような関数を書くことを提案しています:

function sayHello() {
   //Some comments explaining the next line
   window.alert("Hello");
}

難読化以外に、実際にこのようなものを書くことには利点がありますか?もしそうなら、利点は何ですか?

21
Daniel

これが間違っているとしたら、私の記憶をご容赦ください... Javascriptは私の好みの実装言語ではありません。

引数のない関数に別の関数呼び出しをラップさせたい理由はいくつかあります。 window.alert("Hello");の単純な呼び出しは、sayHello()の代わりに直接呼び出す代わりに想像できるものです。

しかし、それ以上のものがある場合はどうなりますか? sayHello()を呼び出したい場所が12か所あり、代わりにwindow.alert("Hello");を記述しています。次に、window.alert("Hello, it is now " + new Date())を実行します。これらの呼び出しをすべてsayHello()としてラップした場合は、1箇所変更します。変更しなかった場合は、12か所で変更します。 Do n't Repeat Yourself に触れます。将来、何十回もやりたくないからです。

私は過去に i18n/l10n ライブラリを使用して、テキストをクライアント側でローカライズする関数を使用していました。 sayHello()関数を考えます。ユーザーがスペイン語にローカライズされている場合は、holaを出力することができます。これは次のようになります。

function sayHello() {
  var language = window.navigator.userLanguage || window.navigator.language;
  if(language === 'es') { window.alert('Hola'); }
   else { window.alert("Hello"); }
}

しかし、これはライブラリが機能する方法ではありません。代わりに、次のような一連のファイルがありました。

# English file
greeting = hello
# Spanish file
greeting = hola

次に、ライブラリはブラウザの言語設定を検出し、適切なローカリゼーションファイルに基づいた引数なしの関数呼び出しの戻り値として適切なローカリゼーションを使用して 動的関数の作成 を検出します。

私はそれが良いか悪いかを言うのに十分なJavaScriptコーダーではありません...それが可能であり、可能なアプローチと見なすことができるというだけです。

つまり、別の関数への呼び出しを独自の関数でラップすることは非常に便利であり、アプリケーションのモジュール化に役立ち、コードが読みやすくなる場合もあります。

余談ですが、チュートリアルから作業しています。最初はできるだけ簡単に紹介する必要があります。 varargsスタイルの関数呼び出しを最初から導入すると、一般的なコーディングに不慣れな人にとって、非常に混乱するコードになる可能性があります。引数なしから引数へ、varargsスタイルへと移行する方がはるかに簡単です。前の例に基づいて構築し、理解してください。

60
user40980

実装を隠すのに役立つこともあると思います。

 function sayHello() {
  window.alert("Hello");
 }

これにより、後で変更する柔軟性が得られます

 function sayHello() {
  console.log("Hello");
 }
34
Sleiman Jneidi

難読化以外に、実際にこのようなものを書くことには利点がありますか?もしそうなら、利点は何ですか?

  • 集中化:実装は1行ですが、頻繁に変更される行の場合は、sayHelloが呼び出される場所ではなく、1か所で変更することをお勧めします。

  • 依存関係の最小化/非表示:クライアントコードはウィンドウオブジェクトがあることを知る必要がなくなり、クライアントコードにまったく影響を与えることなく実装全体を変更することもできます。

  • 契約履行:クライアントコードは、sayHello関数を持つモジュールを想定している場合があります。この場合、たとえ些細なことであっても、機能はそこになければなりません。

  • 抽象化レベルの一貫性:クライアントコードが高レベルの操作を使用する場合、ウィンドウオブジェクトではなく、「sayHello、sayBye」およびその他の「sayXXX」関数の観点からクライアントコードを記述することは、あなたにとって興味深いことです。実際、クライアントコードでは、「ウィンドウ」オブジェクトなどが存在することを知りたくないかもしれません。

19
utnapistim

他の誰もテストに言及していないことは驚くべきことです。

選択した特定の「ラップされた」行window.alert('hello')は、実際にはこれの完璧な例です。 windowオブジェクトに関係するものはすべて、実際にはreallyをテストするのは面倒です。アプリケーションでそれを1000倍にしてください。そうすれば、開発者は最終的にテストをあきらめることになります。一方、sayHello関数をスパイでたどって、呼び出されたことをテストするのは非常に簡単です。

より実用的な例-実際、誰が実際に量産コードでwindow.alert(...)を使用しているのですか? -システムクロックをチェックしています。したがって、たとえば、これは.NETでは_DateTime.Now_、C/C++ではtime(...)、JavaではSystem.currentTimeMillis()をラップすることになります。あなたは本当に注入できる依存関係にそれらをラップしたいのですが、それらはモック/偽造することが(ほとんど)不可能であるだけではないため、これらは読み取り専用で非決定的です =。システムクロック関数を直接使用する関数またはメソッドを対象とするテストは、断続的な障害やランダムな障害の影響を受ける可能性が非常に高くなります。

実際のラッパーは1行の関数-_return DateTime.Now_-ですが、設計が不十分でテスト不可能なオブジェクトを取得して、クリーンでテスト可能なオブジェクトにするために必要なのはこれだけです。ラッパーの代わりに偽の時計を使用して、その時間を任意に設定できます。問題が解決しました。

7
Aaronaught

Dovalが言ったように、この例はおそらく関数を紹介しようとしているだけです。私は一般的ですが、それは便利です。特に、すべてではないが一部の引数を指定し、他の引数を渡すことにより、より一般的な関数からよりケース固有の関数を作成できます。やや平凡な例として、配列をソートするためのソート関数と、ソートのためのコンパレーター関数を考える。数値で比較するコンパレーター関数を指定することで、sortByNumericalValue関数を作成でき、その関数の呼び出しがより明確で簡潔になります。

2
raptortech97

あなたの質問の背後にある考えは、「なぜalert("Hello");を直接書くだけではないのですか?それは非常に簡単です。」

答えは、一部には、本当にalert("Hello")を呼び出したくないためです-ただ挨拶したいだけです。

または:電話番号をダイヤルするだけで連絡先を電話に保存するのはなぜですか?あなたはそれらすべての数字を覚えたくないので;番号をダイヤルするのは面倒でエラーが発生しやすいためです。数は変わるかもしれませんが、それでも相手は同じ人です。数字ではなくpeopleを呼び出したいからです。

これは、抽象化、間接参照、「実装の詳細を隠す」、さらには「表現力豊かなコード」などの用語によって理解されるものです。

生の値をどこにでも書き込むのではなく、定数を使用する場合にも同じ理由が当てはまります。あなたcouldπが必要になるたびに_3.141592..._と書くだけですが、ありがたいことに_Math.PI_があります。

alert()自体も確認する場合があります。アラートダイアログをどのように作成して表示するかは、だれが気にしますか?ユーザーに警告するだけです。 alert("Hello")を書いてから画面のピクセルが変化するまでの間に、コードとハードウェアの深いスタックがあり、各レイヤーは次に何が必要かを伝え、次のレイヤーは最も深いところまで詳細を処理します可能なレイヤーは、ビデオメモリの一部のビットを反転します。

こんにちはと言って自分ですべてをやる必要は本当にありません。

プログラミング-ええと、実際のタスクはすべて、複雑な問題を扱いやすいチャンクに分割することです。各チャンクを解決することでビルディングブロックが得られ、十分なシンプルなビルディングブロックで大きなものを構築できます。

代数です。

2
Flambino