JavaScriptで関数を定義するためのconstの適切な使用


183

constJavaScriptで特定の関数を使用して設定できる値のタイプに制限があるかどうかに興味があります。これは有効ですか?動作することは確かですが、なんらかの理由で悪い習慣と見なされていますか?

const doSomething = () => {
   ...
}

ES6では、このようにすべての関数を定義する必要がありますか?もしそうなら、これは流行っていないようです。

コメントありがとうございます!


複数の質問をしているようです:1)「JavaScriptでconstを使用して設定できる値のタイプに制限があるかどうかに興味があります」番号2)「これは有効ですか?」はい。3)「なんらかの理由で悪い習慣と見なされていますか私はそれについて何かを言うのに十分なほど長く存在していなかったと思いますが、これがなぜパッドの練習であるべきなのかわかりません。と大差ありませんvar doSomething = <function def>;。4)「すべての関数をES6でこのように定義する必要がありますか?」私には扱いにくいようです。関数宣言が好きです。みんな自分のもの。
Felix Kling

1
私の見方(事実ではなく意見)では、関数の再定義を許可しない場合は理にかなっています。それが正気であるか、それともいくつかの機能的な用途があるかどうか-それは議論の余地があります。それがあなたの使用シナリオに適していると思うなら、誰かがあなたの決定を主張してそれを悪い習慣と見なすことはできないと思います。
Mjh

4
問題はあなたが何を達成したいのかだと思いますconst。関数をオーバーライドできないようにしますか?とにかくこれを行わないコードを知っていると思います。の意図doSomething、つまり、関数を保持し、その値を変更しないことを表現しますか?関数宣言もこの意図を明確に伝えていると思います。したがって、オーバーライドからの「ランタイム保護」が必要な場合は、それを実行してください。そうでなければ私は多くの利益を見ていません。もちろん、主にを使用していた場合はvar foo = function() {};、のconst代わりに使用しますvar
Felix Kling、2015年

5
@FelixKling、「とにかくこれを行わないコードを知っていると思います。」-これはかなり悪い議論です。そうでなければ、まったく意味がありませんconst
meandre

回答:


253

何を行っても問題はありませんが、関数宣言と関数式の違いを覚えておく必要があります。

関数宣言、つまり:

function doSomething () {}

スコープの最上部まで完全に巻き上げられます(同様にletconstブロックスコープも同様です)。

これは、以下が機能することを意味します:

doSomething() // works!
function doSomething() {}

関数式、つまり:

[const | let | var] = function () {} (or () =>

匿名関数(function () {})の作成と変数の作成、そしてその匿名関数のその変数への割り当てです。

したがって、スコープ内での変数のホイストに関する通常のルール-ブロックスコープの変数(letおよびconst)はundefined、それらのブロックスコープの上部に関してはホイストしません。

これの意味は:

if (true) {
    doSomething() // will fail
    const doSomething = function () {}
}

doSomething定義されていないため失敗します。(それはスローされます ReferenceError

使用に切り替えるとvar、変数のホイストが取得されますが、初期化されるundefinedため、上記のコードのブロックは機能しません。(これがスローされますTypeErrorので、doSomethingあなたはそれを呼び出す時には関数ではありません)

標準的な方法では、ジョブに適切なツールを常に使用する必要があります。

Axel Rauschmayerが、es6のセマンティクスを含むスコープとホイストに関する素晴らしい投稿を持っています:ES6での変数とスコープ


7
es6クラスが内部でconstを使用してクラス名がクラス内で再割り当てされないように保護することを追加したいだけです。
user2342460 2017

2
間の1つの微妙な違いとbがあなたのようにそれを呼び出す場合であるで、それが印刷される中、B、それが印刷されます。 function a(){console.log(this);} const a=_=>{console.log(this);}a.call(someVar);someVarwindow
Qian Chen

100

const関数の定義に使用することはハックのように見えますが、それを優れたものにするいくつかの大きな利点があります(私の意見では)

  1. これにより関数が不変になるため、他のコードによって関数が変更されることを心配する必要はありません。

  2. ファットアロー構文を使用できます。これは、短くて簡潔です。

  3. アロー関数を使用すると、thisバインディングが処理されます。

function

// define a function
function add(x, y) { return x + y; }

// use it
console.log(add(1, 2)); // 3

// oops, someone mutated your function
add = function (x, y) { return x - y; };

// now this is not what you expected
console.log(add(1, 2)); // -1

同じ例 const

// define a function (wow! that is 8 chars shorter)
const add = (x, y) => x + y;

// use it
console.log(add(1, 2)); // 3

// someone tries to mutate the function
add = (x, y) => x - y; // Uncaught TypeError: Assignment to constant variable.
// the intruder fails and your function remains unchanged


1
また、関数add(x、y)を2回宣言することはできますが、const add = ...を2回宣言することはできません
TatianaP

33
1.不変性は真のメリットですが、実際に関数を上書きすることは非常にまれです。2.関数が式である場合を除き、太い矢印の構文は短くなりません。function f(x, y) {は18文字、const f = (x, y) => {21文字なので、3文字長くなります。3.このバインディングを維持することは、関数がメソッド(またはこれに意味のある他の関数)内で定義されている場合にのみ重要です。トップレベルのスクリプトではそれは無意味です。あなたが間違っていると言っているのではなく、あなたが言及する理由がひどく関連していないというだけです。
Nakedible

@Nakedibleだから、他に有効な理由は何ですか?
アニッシュラマスワミー

13
昔ながらの関数構文の利点の1つは、デバッグ時に名前が付けられることです。
user949300

3
関数宣言の再バインドを防ぐためにリンターを使用します。
フランクリンYu

32

この質問が出されてから3年が経過しましたが、私はたまたまそれに出くわしました。この答えはスタックのはるか下にあるので、繰り返してみましょう。

Q: JavaScriptでconstを使用して設定できる値のタイプ、特に関数に制限があるかどうか興味があります。これは有効ですか?動作することは確かですが、なんらかの理由で悪い習慣と見なされていますか?

明らかな理由/メリットがない場合でも、常にのconstステートメントを使用する1つの多作なJavaScriptコーダーを観察した後、私はいくつかの調査を行う動機がありましたfunctions

なんらかの理由で悪い習慣と見なされていますか?」と答えると、IMO、そうです、そうです、または少なくとも、ステートメントを使用することには利点がありますfunction

これは主に好みとスタイルの問題であるように私には思えます。上記のいくつかの良い議論がありますが、この記事で行われているほど明確ではありません。

一定の混乱:なぜ、media.freecodecamp.org / Bill Sourour、JavaScriptの第一人者、コンサルタント、教師によるJavaScript関数ステートメントをまだ使用しているのか

あなたがすでに決定を下したとしても、私は皆にその記事を読むことを勧めます。

主なポイントは次のとおりです。

関数ステートメントには、[const]関数式に比べて2つの明確な利点があります。

利点#1:意図の明確さ

1日に数千行のコードをスキャンする場合、プログラマの意図を可能な限り迅速かつ簡単に把握できると便利です。

利点#2:宣言の順序==実行の順序

理想的には、コードが実行されると予想される順序でコードを多かれ少なかれ宣言したいです。

これは私にとっての魅力です。constキーワードを使用して宣言された値は、実行に到達するまでアクセスできません。

上記で説明した内容により、逆さまに見えるコードを作成する必要があります。最も低いレベルの関数から始めて、上に向かって進む必要があります。

私の脳はそのように機能しません。詳細の前にコンテキストが欲しい。

ほとんどのコードは人間によって書かれています。したがって、ほとんどの人の理解の順序は、大部分のコードの実行順序にほぼ従うことは理にかなっています。


1
意図の明確さについてもう少しコメントできますか?私は#2を取得しますが、私の知る限り、#1は#2の単なる(事前?)反復です。私はケースを考えることができます。つまり、独自のdefaultErrorHandlerconstが無名関数として割り当てられており、promiseハンドラーから呼び出すことができます。これにより、必要に応じて、オプションでこのデフォルトのエラーハンドラーを関数内で「オーバーライド」できます。エラーオブジェクトを返す必要があるものもあれば、さまざまなレベルの冗長性を持つhttp応答を返す必要があるものもあります。それでも、コード構造はどのようなパターンでもおなじみのパターンになります。
ジェイク

多分私の考えはあまりにも複雑です!いくつかの新しいプラクティスに頭を抱えただけで、まだそれらの実装に大量の時間を費やしていません。ただ.then( res.success, res.error )呼び出すことを宣言した無名関数よりも本当に好きだということがわかりましたres.success(value);.then( ..., defaultErrorHandler)共通のパターンを持つことは、トップレベルで定義されたdefaultErrorHandler関数を使用して、オプションで、必要に応じてconst defaultErrorHandler = error => { ... }関数スコープ内で宣言することもできます。
Jake T.

1
@JakeT。RE「意図の明確さについてもう少しコメントしていただけますか?」まあ、最初に、その発言は私ではなく、その記事の著者であるfreecodecamp.org/Bill Sourourによって行われました。しかし、それは私には本当の常識です。「関数tomorrow()」を読むと、それが関数であることがすぐにわかります。しかし、「const tomorrow =()=>」と読んだら、しばらく停止して頭の中で構文を解析し、最終的に決定します。そうです、それは関数です。
JMichaelTX 2018

1
また、誰かが長いスクリプトを書いていて、すべての関数を確認したい場合は、「関数」で簡単に検索してそれらを見つけることができます。またはさらに良いことに、すべての関数を抽出するための簡単なJS RegExを作成できます。IMO、「const」ステートメントは、変更されないデータ(関数ではない)専用です。
JMichaelTX 2018

10

を使用することにはいくつかの非常に重要な利点があり、constそれがいかに故意であり、示唆的であるために、可能な限り使用する必要があると言う人もいます。

これは、私が知る限り、JavaScriptでの変数の最もわかりやすく予測可能な宣言であり、その制約の最も有用な理由の1つです。どうして?それは、利用可能ないくつかの可能性varlet宣言を排除するためです。

あなたが読んだときに何を推測できますconstか?const宣言ステートメントを読むだけで、その変数への他の参照をスキャンしなくても、次のすべてを知ることができます。

  • 値はその変数にバインドされます(ただし、その基になるオブジェクトは深く不変ではありません)
  • 直接包含しているブロックの外からはアクセスできません
  • Temporal Dead Zone(TDZ)ルールのため、宣言の前にバインディングにアクセスすることはありません。

次の引用は、およびの利点を論じている記事からの引用です。また、キーワードの制約/制限に関する質問に、より直接的に回答します。letconst

こうしたによって提供されるものなどの制約letconst理解しやすいコードを作成する強力な方法です。記述するコードでこれらの制約をできるだけ多く発生させるようにしてください。コードの一部が何を意味するかを制限する宣言的な制約が多いほど、将来、人間がコードの一部を読み取り、解析し、理解することがより簡単かつ高速になります。

確かに、const宣言よりも宣言にはより多くのルールがありますvar。ブロックスコープ、TDZ、宣言時に割り当て、再割り当てなし。一方、varステートメントは関数のスコープのみを通知します。ただし、ルールカウントは多くの洞察を提供しません。複雑さの観点からこれらのルールを比較検討することをお勧めします。ルールは複雑さを追加または減算しますか?の場合const、ブロックスコープは関数スコープよりもスコープが狭いことを意味し、TDZは宣言の前に使用法を見つけるために宣言からスコープを逆方向にスキャンする必要がないことを意味し、割り当て規則はバインディングが常に同じ参照。

制約のあるステートメントが多いほど、コードの一部が単純になります。ステートメントの意味に制約を追加すると、コードの予測が難しくなります。これは、静的に型付けされたプログラムが動的に型付けされたプログラムよりも一般に読みやすい最大の理由の1つです。静的型付けはプログラム作成者に大きな制約を課しますが、プログラムの解釈方法にも大きな制約を課し、コードを理解しやすくします。

これらの議論を念頭に置いて、const考えられる可能性が最も少ないのはステートメントなので、可能な限り使用することをお勧めします。

ソース:https : //ponyfoo.com/articles/var-let-const

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.