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


21

私がやっているチュートリアル(Javascript用)では、次のような関数を作成することをお勧めします。

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

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


14
おそらく、独自の関数を定義する方法を説明しようとしているだけです。
ドーバル14年

4
私はそれを難読化するような方法でコードを書くことは決してありません-コードはプログラマーが簡単に読むためのものであり、その逆ではありません。難読化には難読化ツールを使用します。
rhughes 14年

32
利点は、関数パラメーターでラップすることです。この方法で、後でアプリをスペイン語にしたい場合は、「Hello」を「Ola」に1か所で変更するだけです。
ピーターB 14年

9
@PieterB実際には、 "はいはい"
REV

29
@PieterB-「Hola」のつづりを間違えた場合は、1か所で修正するだけです。
ダニエルRヒックス14年

回答:


60

これが正しくない場合は、私の記憶をご容赦ください... Javascriptは、私の好みの実装言語ではありません。

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

しかし、それだけではありませんか?電話をかけたい場所が十数か所あり、代わりにsayHello()書きwindow.alert("Hello");ました。今、あなたはそれを実行したいwindow.alert("Hello, it is now " + new Date())。これらの呼び出しをすべてsayHello()1か所で変更するときにラップします。変更しなかった場合は、12か所で変更します。これは繰り返さないください。あなたが将来何十回もそれをする必要がないので、あなたはそれをします。

私は過去に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スタイルの関数呼び出しを最初から導入すると、一般的なコーディングに不慣れな人にとっては非常にわかりにくいコードになる可能性があります。引数なしから引数、可変引数スタイルへの移行は、前の例と理解に基づいて各建物を作成する方がはるかに簡単です。


3
window.alertまた、開発中に素敵なモーダル/ポップアップを設計/実装できるようになるまでプレースホルダーとして使用されることが多いため、言語の問題と同様に、はるかに簡単に切り替えることができます。または、すでにある場合は、数年後の設計更新でも同様の変更が必要になる場合があります。
イズカタ14年

34

実装を隠すために時々役立つと思います。

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

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

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

19

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

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

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

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

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


私はこの答えが好きです。多くの場合、デザインはこれらの機能の主な理由です。特に、特定の動作を行う他のオブジェクトの機能を実行するオブジェクトを動作させるオブジェクト指向デザインでは特にそうです。あなたの車、より具体的にはギアのシフトをイメージングします。ギアをシフトアップするには、スティックを「伝える」ことによってシフトアップします。次に、この呼び出しをギアボックスに転送します。しかし、それに加えて、最初に現在の位置からシフトできるかどうかをチェックします。
エリック14年

3
他の理由は良いですが、抽象化レベルに言及する場合は+1です。明確な抽象化と適切な関数名を使用すると、古いコードの読み取りと保守がはるかに簡単になります。sayHello()が呼び出される時点で、必ずしもその実装方法を気にする必要はありません。このコード行の意図を理解したいだけです。そして、sayHello()のような関数名はそれを明白にします。
kkrambo 14年

また、抽象化レベルに言及するための+1:1つの抽象化レベルでの関数の実装が、より低い抽象化レベルの別の関数への1回の呼び出しで構成される場合があります。だから何?
ジョルジオ14年

7

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

あなたが選んだ特定の「ラップされた」行window.alert('hello')は、実際にはこれの完璧な例です。関係する何かwindowオブジェクトは、本当に、本当にテストに痛いです。アプリケーションでそれを1000倍すると、開発者が最終的にテストを断念することを保証します。一方、sayHelloスパイを使用して関数を上書きし、呼び出されたことをテストするのは非常に簡単です。

より実用的な例-本当に、誰が実際window.alert(...)に生産コードで使用するのですか?-システムクロックをチェックしています。そのため、たとえば、これはDateTime.Now.NET、time(...)C / C ++、またはSystem.currentTimeMillis()Java でラップされます。あなたは本当に彼らがいないだけで(ほぼ)模擬することは不可能/偽物が、あるので、あなたが注入できることに依存して、それらをラップしたい、彼らは読み取り専用と非決定的。システムクロック機能を直接使用する機能または方法を対象とするテストは、断続的および/またはランダムな障害に陥る可能性が非常に高くなります。

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


2

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


2

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

答えは、部分的には、電話をかけたくないからですalert("Hello")- ただ挨拶したいだけです。

または:電話番号をダイヤルするだけで連絡先を電話に保存するのはなぜですか?これらの数字をすべて覚えたくないので。ダイヤル番号は退屈でエラーが発生しやすいためです。番号が変更される可能性がありますが、それでも相手側では同じ人です。番号ではなくに電話をかけたいからです。

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

同じ理由が、生の値をどこにでも書き込む代わりに定数を使用する場合にも当てはまります。πが必要になるたびに書くことができ3.141592...ますが、ありがたいことにありMath.PIます。

また、alert()自分自身を見ることもあります。アラートダイアログをどのように構築して表示するのか誰が気にしますか?ユーザーに警告したいだけです。書くことalert("Hello")と画面上のピクセルが変化することの間には、コードとハードウェアの深いスタックがあり、各レイヤーは次に何が欲しいかを伝え、その次のレイヤーは可能な限り深いレイヤーがいくつかのビットを反転するまで詳細を処理しますビデオメモリ。

あなたは本当に挨拶するためだけにすべて自分でやる必要はありません。

プログラミング(まあ、どんなタスクでも)は、複雑な問題を管理可能なチャンクに分割することです。各チャンクを解くことで構築ブロックが得られ、十分な単純な構築ブロックで、大きなものを構築できます。

代数です。


-1

(式)の計算をアクション(ステートメント)の実行とは別にすることをお勧めします。アクションを実行する場所とタイミング(メッセージの表示など)を正確に制御する必要がありますが、値を計算するときは、より抽象的なレベルで作業し、それらの値の計算方法を気にする必要はありません。

指定された引数のみを使用して戻り値のみを計算する関数は、pureと呼ばれます。

アクションを実行する「関数」は実際にはプロシージャであり、効果があります

値の計算中に引き起こされる影響は副作用と呼ばれ、可能な場合は回避するほうが良いです(「その文字列が必要だったので、データベースを破壊することは知りませんでした!」)。

副作用の可能性を最小限に抑えるために、プロシージャに大量のデータを送信したり、プロシージャに計算を入れたりしないでください。事前に何らかの計算を実行する必要がある場合は、通常、純粋な関数で個別に実行し、必要な結果のみをプロシージャに渡す方が適切です。これにより、手順の目的が明確に保たれ、後で計算の一部として再利用される可能性が低くなります(純粋な関数を代わりに再利用できます)。

同じ理由で、プロシージャ内で結果を処理することは避けてください。結果(ある場合)をアクションに返し、その後の処理を純粋な関数で実行することをお勧めします。

これらのルールに従うと、sayHelloデータを必要とせず、結果を持たないのような手順になる可能性があります。したがって、これに最適なインターフェイスは、引数を持たず、値を返さないことです。これは、たとえば、計算の途中で「console.log」を呼び出すよりも望ましい方法です。

計算中の効果の必要性を減らすために、プロシージャ返す計算を使用できます。例えば。実行するアクションを決定する必要がある場合、直接実行するのではなく、純粋な関数でプロシージャを選択して返すことができます。

同様に、プロシージャ中の計算の必要性を減らすために、プロシージャに他のプロシージャをパラメータとして(おそらく関数の結果として)取得させることができます。例えば。一連の手順を実行し、次々に実行します。


あなたはここでOOPに反対しているようです、そこでは基本的な原則は「教えてください、尋ねないでください」です。ここでのアドバイスに従うと、通常は無用の「getFoo」、「setFoo」、「execute」の呼び出しで混乱したコードになります。OOPはデータと動作を分離するのではなく、結合することです。
アーロンノート14年

@Aaronaught私がOOPに反対しているのは事実ですsetFooが、変更可能なデータを意味するため、呼び出しはお勧めしません。変数/プロパティの内容を変更すると効果があり、そのデータを使用するすべての計算が不純になります。私はお勧めしませんexecuteそれ自体のコールを、私は考えをお勧めしますrunFooその引数に基づいてアクションを実行するための手順を。
ウォーボ14年

-2

@MichaelTと@Sleiman Jneidiの回答の組み合わせだと思います。

おそらく、コード内に、ユーザーにHelloメッセージで挨拶したい場所がいくつかあるので、そのアイデアをメソッドに詰め込みます。このメソッドでは、長いテキストを表示して翻訳したり、単純な「Hello」に展開したりできます。また、アラートの代わりに素敵なJQueryダイアログを使用することもできます。

ポイントは、実装が1か所にあることです。コードを1か所で変更するだけです。(SayHello()はおそらく単純すぎる例です)


@downvoter(s)-あなたの知識を他の人と共有するように気をつけてください。私の投稿は単純に間違っているか、不適切に書かれているか、それとも何ですか?
ポール14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.