Sébastien TIMONER
Web開発と技術チーム管理のエキスパートとして、高性能なデジタルソリューションの作成と最適化を専門としています。React.js、Node.js、TypeScript、Symfony、Docker、そしてFrankenPHPなどの最新技術における豊富な専門知識を活かし、様々な業界の企業向けに、設計から本番環境までの複雑なSaaSプロジェクトの成功を確実にします。
JavaScriptの変数で頭を抱えている開発者の皆さん!チームミーティングでvar、let、constの使い分けに困ったことはありませんか?心配いりません。一緒に楽しく解決していきましょう。各キーワードを探求し、スコープ(グローバル、関数、ブロック)を比較し、ホイスティング(JavaScriptのちょっと不思議な機能)について議論し、実践的な例を提供し、最後にTypeScriptについても触れていきます。準備はいいですか?それでは始めましょう!
まずはvarから始めましょう。JavaScriptの変数の中でも「大先輩」です。JavaScriptがドラマだったら、varは古風で予測不可能なキャラクターでしょう。ES5以前は、変数を宣言するにはvarしかありませんでした。今でも使うことはできますが、注意が必要です:いくつかの驚くべき特性があります。
var x = 1; var x = 2;
はエラーを引き起こしません——JavaScriptは単に最初の値を2番目の値で上書きします。古いコードでは便利ですが、新しいコードでは混乱の原因となるので避けるべきです。varの広すぎるスコープを小さな例で説明しましょう:
javascript
はい、このfruitはif文の中で宣言されているにもかかわらず、ブロック外のconsole.logでも問題なくアクセスできます。varはブロックの境界を気にしません:グローバルか、それを含む関数のどちらかです。
最後に、ホイスティングについて話しましょう。日本語では「巻き上げ」と呼ばれることもありますが、正直なところ、私たちは主にhoistingという用語を使います。これはvarがスコープの先頭で静かに宣言される傾向のことです。JavaScriptは実行時に、すべてのvar宣言が関数の先頭に「巻き上げられた」かのように振る舞います。そのため、宣言の前でも変数を使用できます...ただし、少し奇妙な値が得られます。この問題については、後ほどホイスティングのセクションで詳しく説明します(ネタバレ:varはundefinedで驚かせるのが大好きです)。
全体として、varは私たちに良いサービスを提供してきましたが、いくつかの狡猾な特性があります:広すぎるスコープ、静かな再宣言、予測不可能なホイスティング...もっと良い方法があります。幸いなことに、ES6は新しいキーワードを導入して、すべてを整理しました。
2015年、JavaScriptはlet(とconst)を迎え入れました。そして、変数宣言の小さなアップグレードを得ました。letはクールで規律正しい若者のようなものです:varのほとんどの癖を修正しながら、柔軟性を保っています。
let x = 1; let x = 2;
と書こうとすると、素敵な SyntaxError: Identifier 'x' has already been declared
エラーが発生します。これで多くの混乱を避けられます。varをletに置き換えて、スコープの違いをはっきりと見てみましょう:
javascript
letを使うと、if文の波括弧を出た瞬間に終わりです。vegetable変数はもはや定義されていません。アクセスしようとすると:ReferenceErrorが発生します。これがletが良好なスコープの振る舞いを強制する方法です。
では、ホイスティングはどうでしょうか?let(とconst)変数もホイスティングされますが、方法が異なります。宣言前には使用できません。技術的には、JSエンジンはブロック内に変数が存在することを知っています(メモリを確保します)が、宣言文が実行されるまでは、アクセスしようとするとエラーが発生します。これらの変数は一時的なデッドゾーンにあると言います(はい、ホラー映画のように聞こえますが、これは「初期化前はアクセス不可」の洒落た言い方です)。この振る舞いについては後で詳しく説明しますが、letは変数を早すぎる段階で使用させないことを覚えておいてください。
実際には、letは時間とともに変化する変数のデフォルト選択肢となりました。明確さ(ブロックスコープ)と安全性(予期しない再宣言なし、宣言前のアクセスなし)をもたらします。簡単に言えば、letは一時的または変更可能な変数を宣言するための新しい友達です。
次はconstです!letと同時に導入され、このキーワードは定数を作成します...と言いたいところですが、そうではありません。参照が変更されない変数を作成します。constはletと同じブロックスコープ(もうvarがうろつくことはありません)と同じホイスティングルール(宣言までの一時的なデッドゾーン)を持っています。大きな違いは、一度初期化されると、変数は再代入できなくなることです。
const x;
だけでは動作しません(直接SyntaxError)。const x = 42;
のように書く必要があります。変更可能な変数との違いを明確に示す小さな例を見てみましょう:
javascript
PIを定数として定義し、変更しようとしなければ問題なく使用できます。PI = 3.15を試みると、JavaScriptは即座に私たちを止めます:定数は変更できません。
注意:定数は100%不変という意味ではありません。値がオブジェクトや配列の場合、オブジェクト/配列の内部は変更できます。変更できないのは変数自体(メモリ内の参照)です。例えば:
javascript
ここでは、constを使用しているにもかかわらず、userオブジェクトのnameを変更できました。しかし、userを完全に別のオブジェクトに再代入することは禁止されています。したがって、const = 定数、変更不可、ただし変数自体のレベルでのみです。変数の定数性と値の不変性を混同しないでください。
javascript
配列の場合も同じロジックです:内容を変更できます(要素の追加、削除、変更)が、fruits変数を新しい配列に再代入することはできません。配列が箱のようなものだと考えると:中身は変更できますが、箱自体を置き換えることはできません。
実際には、constは変更されるべきでない値に最適です:例えば設定、参照など。広く使用され、コードをより堅牢にします(この変数が動かないことがわかっています)。実際、ベストプラクティスでは、デフォルトでconstを使用し、値が変更される必要があることがわかっている場合のみletに切り替えることを推奨しています。varについては...まあ、特別な理由がない限り、忘れましょう 😉。
スコープについてもっと話しましょう。スコープは変数がコード内の「どこ」でアクセス可能かを決定します。JavaScriptには主に3つのスコープレベルがあります:
まとめると:varは関数(またはグローバル)に制限され、letとconstは現在のブロックに制限されます。この違いは多くの古典的な問題を解決します。例えば:
javascript
ここでは、varを使用したループはiを外に残し、最終値3を持っています。letを使用したループは、一方で、終了時にjをクリーンアップします:その後アクセスできません。実際には、これは異なるブロックで同じ名前のlet変数を使用でき、相互に干渉しないことを意味します。一方、単一のvarはこれらのブロック間で共有されます。
ホイスティングについて話しましょう。この宣言の巻き上げメカニズムは、しばしば混乱の源(そして会議でのジョーク)になります。ホイスティングは、JavaScriptエンジンが実行中に変数と関数の宣言をそれらのスコープの先頭に「移動」する動作です。実際には、コード内で何かが本当に移動するわけではありません。これはJavaScriptが実行前に変数のメモリを事前に割り当てるだけです。
実際にホイスティングをテストしてみましょう:
javascript
最初のconsole.logの時点で、myVar変数はホイスティングによってメモリ内に作成されていますが、そのデフォルト値はundefinedです(まだ代入していないため)。エラーはなく、undefinedが表示されるだけです。その後「こんにちは」を代入し、2回目は期待通りの値が得られます。
次にletを見てみましょう:
javascript
ここでは、最初のconsole.logがReferenceErrorを引き起こします。なぜ?myLetはホイスティングされますが初期化されないためです。それは一時的なデッドゾーンにあり、アクセスできません。JavaScriptはまだ本当に存在しない値を私たちに与えることを拒否します。let myLet = "こんにちは";
を実行すると、変数は一時的なデッドゾーンを出て「こんにちは」を取得します。2番目のconsole.logは完璧に動作します。
はっきりと見えるように:varは忍者のように宣言を巻き上げて静かにundefined値を自分に与えますが、let/constは安全策を講じ、初期化されるまで使用を防ぎます。教訓:ホイスティングに頼ってコーディングするのは避けましょう。それは脳の結び目(と予期しないundefined)のレシピです。スコープの先頭で変数を宣言し、コードをクリーンに保つのが最善です。忘れた場合、let/constの振る舞いがエラーで思い出させてくれます。varはundefinedで苦労させていたでしょう。
あ、そうそう、従来の関数宣言(function myFunction() \{ ... \}
)も完全にホイスティングされることに注意してください。コードの後方で宣言された関数を呼び出すことができ、JavaScriptはすでにそれを知っています。ただし、アロー関数や変数に代入された関数式は、使用されるキーワードに応じてvar/letのホイスティングルールに従います(これは別の日の話題 😉)。
終わる前に、TypeScriptについて簡単に話しましょう。TypeScript(JavaScriptに静的型付けを追加するスーパーセット)を使い始めると、私たちの3人の友達var、let、constに出会います。良いニュース:それらのスコープとホイスティングの振る舞いは純粋なJavaScriptとまったく同じです。TypeScriptは標準JavaScriptにコンパイルされるためです。しかし、TypeScriptは型付けの面で独自の特色を持ち、特にletとconstについては見る価値があります。
let fruit = "りんご";
と書くと、TypeScriptはfruitがstring型だと推論します。let age = 25;
と書くと、ageが数値だと理解します。letの場合、かなり広範です:変数は変更可能なので、型は基本型(string、numberなど)です。typescript
color変数は"赤"型であり、単なるstringではありません。利点?後でコードが正確に"赤"または"青"の値を期待する場合(例えば、これらの色のいずれかしか受け付けないパラメータ)、const color = "赤"
があれば、心配なく渡せます。let color = "赤"
(広範なstring型)では、TypeScriptは文句を言うでしょう。"赤"はすべての文字列の中の1つの可能性に過ぎないからです。簡単に言えば、TypeScriptのconstは有用な時に超精密な型定義を可能にします。これは定数の概念をさらに強化するボーナスのようなものです。
console.log(myVar); var myVar = 3;
と書くと、スコープや順序の問題があることを指摘します。letを早すぎる段階で使用する場合も同様で、TSはホイスティングルールを知っており、可能な限りエラーから保護します。まとめると、TypeScriptはvar/let/constの基本ルールを変更しませんが、型システムの安全ネットでそれらを強化します。明確さを得て、エラーをより早くキャッチします。特にTypeScriptのconstは二重の勝利であることを覚えておいてください:再代入不可能な変数と正確なリテラル型——これ以上何を求めることができますか?
すべてをカバーしました。では、var vs let vs constの戦いの勝者は誰でしょうか?驚くことではありません:2025年では、let & constの組み合わせが明確で保守可能なコードを書くために圧倒的に勝っています。ここに実践的なアドバイスがあります:
これで、JavaScriptでいつvar、let、またはconstを使用するか、そしてTypeScriptでの動作についても少し理解できました。もう私たちの3人の友達について混乱することも、コードレビューで理由もなくvarを出して笑われることもありません。落ち着いてコーディングに行きましょう。そして忘れないでください:可能な限りconst、必要な場合のみlet、そしてvarは...できるだけ少なく!ハッピーコーディング!