この記事では、JavaScriptにおけるvar/let/constの違いと使い分けを解説します。再代入やスコープの違い、constの安全性や実用例を学ぶことで、効率的かつバグの少ないコードを書く方法が理解できます。
目次
JavaScriptにおける変数宣言とは
varの特徴と課題
JavaScriptが誕生した当初から変数宣言に使われてきたのがvar
です。長い間標準として利用されてきましたが、その挙動にはいくつかの課題が存在します。特にスコープや再宣言の部分で、プログラムの可読性や予期せぬエラーの原因になりやすいため、注意が必要です。
- 関数スコープ:
var
で宣言された変数は関数単位で有効となり、ブロック内に書いたとしても外側からアクセスできてしまいます。 - 再宣言が可能:同じスコープ内で複数回同じ変数を定義できてしまうため、意図せず値が上書きされることがあります。
- 巻き上げ(Hoisting):宣言部分のみがスコープの先頭に巻き上げられる仕様があり、思っていたのと異なる挙動を示すことがあります。
例えば、以下のようにif
ブロック内で宣言した変数に、外部からアクセスできてしまいます。
if (true) {
var x = 10;
}
console.log(x); // 10 と出力される
このように、var
には古い仕様を引きずった特性が多く、チーム開発や規模の大きなシステムではバグの温床になることが少なくありません。そのため、現在ではlet
やconst
といった新しい宣言方法が推奨されています。
constとは何か
constで宣言できる変数の性質
JavaScriptにおけるconst
は、「再代入できない変数」を宣言するためのキーワードです。名前から「定数(constant)」を連想するかもしれませんが、必ずしも値そのものが不変ではなく、変数名と値の紐付けが固定されるという性質を持っています。そのため、const
で宣言した変数は同じ変数名に別の値を再代入することができません。
- 宣言と同時に初期化が必須
- 宣言後に再代入は不可
- ブロックスコープを持つ({} の中で有効)
このような特徴から、const
は意図せぬ再代入を防ぎ、コードの可読性や保守性を高めるために広く利用されています。特に関数やブロックの中で一度決まった値を変更せずに扱いたい場合に適しています。
再代入できない仕組み
const
の変数は「再代入できない」というルールがあります。例えば、一度数値や文字列を代入すると、別の値に書き換えることはできません。これは、JavaScriptエンジンが変数名と値の参照を固定することで実現しています。再代入を試みるとエラーが発生し、プログラム実行が止まってしまいます。
const number = 10;
number = 20; // エラー: 再代入は不可能
この仕組みにより、プログラマーは「この変数は処理の途中で変わらない」という前提で安心してコードを書くことが可能になります。結果としてバグの発生を防ぎ、意図しない副作用を減らせることが大きな利点です。
オブジェクトや配列との組み合わせ
const
で宣言した変数は再代入できませんが、参照しているオブジェクトや配列自体は変更可能です。つまり、const
によって「参照先が変わらない」だけであり、内部の要素を追加したり変更したりすることは許されています。
const arr = [1, 2, 3];
arr.push(4); // OK: 配列の中身は変更可能
console.log(arr); // [1, 2, 3, 4]
const obj = { name: "Alice" };
obj.name = "Bob"; // OK: プロパティの変更は可能
console.log(obj); // { name: "Bob" }
このように、「固定されるのは変数とその参照先の関係」であるため、ミュータブルなオブジェクトを扱う際には注意が必要です。もし内容まで不変にしたい場合には、Object.freeze()
などの補助的なメソッドを活用するとよいでしょう。
分割代入を用いた宣言方法
JavaScriptのconst
は、配列やオブジェクトから特定の要素を取り出す「分割代入」と併用することで、より直感的なコードの記述が可能です。分割代入を使うと、あらかじめ必要な値だけをconst
変数にすることができます。
// 配列の分割代入
const [first, second] = [10, 20];
console.log(first); // 10
console.log(second); // 20
// オブジェクトの分割代入
const { name, age } = { name: "Alice", age: 25 };
console.log(name); // "Alice"
console.log(age); // 25
分割代入とconst
を組み合わせることで、「この値は処理中で変わらない」という明確な意図を示せるため、保守性や可読性の高いコードを書くことができます。特にAPIレスポンスや複雑なオブジェクトを扱う際に有効なテクニックです。
constの基本的な使い方
宣言と初期化のルール
JavaScriptにおけるconst
は「定数」を宣言するためのキーワードです。ただし、単なる数値や文字列の固定に留まらず、オブジェクトや配列など幅広いデータ型を扱うことができます。最大の特徴は、一度宣言した変数を再代入できないという点です。そのため、コーディング時に意図しない値の上書きを避けられる安全性が確保されます。
const
を用いる場合、必ず宣言と同時に初期化を行う必要があります。これはlet
やvar
とは異なる大きな制約です。具体的には以下のように記述します。
// 正しい記述
const PI = 3.14;
// エラーとなる例(初期化していない)
const value;
このように、宣言のみを行うことはできないため、変数の役割を明確にしたい場合や、コード上の意図を確実に伝えたい場合に有効です。特に定数や設定値の定義に適しています。
const
は宣言時に初期値の指定が必須- 再代入は不可能だが、オブジェクトや配列のプロパティ変更は可能
- スコープはブロックスコープに従うため安全
letとconstの違い
再代入の可否
JavaScriptにおいて変数を宣言する際、let
とconst
はよく比較されます。最も大きな違いのひとつが「再代入の可否」です。let
で宣言した変数は後から値を変更できますが、const
で宣言した変数は一度値を設定した後、基本的に再代入ができません。
例えば、カウンターの値を更新するようなケースではlet
が適していますが、一定の定数値を保証したい場合にはconst
を用いることでプログラムの安全性が高まります。意図しない上書きを防ぐという点で、const
は非常に有用です。
再宣言の可否
もうひとつの明確な違いが「再宣言の可否」です。var
とは異なり、let
もconst
も同一スコープ内で同じ名前の変数を再宣言することはできません。この仕様によって、開発者が誤って同じ変数名を複数回宣言してしまうことを防ぎ、コードの可読性や堅牢性を維持することができます。
特に大規模な開発では、変数の重複はバグの温床となりやすいため、let
もconst
も「再宣言できない」という点は大きなメリットといえるでしょう。
スコープの違い
let
とconst
はいずれも「ブロックスコープ」を持ちます。これは、変数が宣言されたブロック(波括弧 { }
)内のみで有効であることを意味します。ただし、グローバルスコープや関数スコープなど、適用される範囲によって挙動に違いがあります。それぞれ詳しく見ていきましょう。
グローバルスコープでの挙動
let
やconst
をグローバルスコープで宣言した場合、それはグローバルオブジェクト(ブラウザ環境でのwindow
)のプロパティには自動的に組み込まれません。これにより、var
のように意図せずグローバル変数と衝突するリスクが小さくなります。
この設計は、より安全で予測可能な挙動を保証する点で重要です。
ブロックスコープでの挙動
let
とconst
はいずれもブロックスコープを持つため、if
文やfor
文の中で宣言した変数は、そのブロックを抜けると参照できなくなります。
この性質により、余計な変数がスコープ外で生き残ることがなく、メモリ効率やコードの明瞭さが改善されます。
関数スコープでの挙動
関数内で宣言されたlet
やconst
変数は、その関数スコープ内でのみ有効です。従来のvar
も関数スコープを持ちますが、var
はブロック単位の制御に対応していません。そのため、より厳密にスコープ管理を行いたい場合には、let
やconst
が推奨されます。特にconst
を用いると、関数内で定数として扱いたい値を確実に固定でき、予期せぬ再代入を防ぐことが可能です。
varとlet/constの使い分け
varの歴史的背景と問題点
JavaScriptの初期から存在する変数宣言の方法がvar
です。初期のWeb開発においては標準的に利用されていましたが、その仕様にはいくつかの問題点があります。特に意識しなければならないのが「関数スコープ」と「巻き上げ(hoisting)」と呼ばれる挙動です。
var
はブロックスコープを持たず、関数内で宣言した変数はそのブロック外からでもアクセスできてしまいます。そのため、意図しない値の上書きやデータの衝突が起こりやすいという欠点があります。また、変数宣言より前にアクセスするとエラーではなくundefined
が返ってしまうため、バグの温床となる場面も多くありました。
- 関数スコープのみを持つため予期せぬスコープ汚染が発生する
- 巻き上げにより可読性が下がり、バグを発見しにくい
- 現代のJavaScriptでは
let
/const
で代替可能
letを選ぶべき場面
let
はES6(ECMAScript 2015)で導入され、var
の欠点を補う役割を担っています。ブロックスコープを持つため、ループや条件分岐ごとに安全に変数を使い分けることが可能になりました。特に値が再代入されるようなケースでは、let
を選ぶのが適切です。
例えば、ループ内でカウンタ変数を利用する場面や、条件に応じて値を更新していく処理ではlet
を使うことで管理が明確になります。また、巻き上げの挙動も制御されているので、宣言前に変数へアクセスするとエラーが発生し、不正なコードを早期に検出できます。
- ループ処理内でカウンタ変数を用いる場合
- 条件ごとに変数の値を切り替える場合
- 再代入が必要な一時的変数を用いる場合
constを選ぶべき場面
const
は「定数」を宣言するために使われますが、実際のところ「再代入できない変数」を意味します。ブロックスコープを持つ点ではlet
と同じですが、宣言時に必ず初期化が必要で、その後の再代入が禁止されます。
コードの意図を明確に伝えるという観点からも、基本的にはconst
をデフォルトで利用し、値を変更する必要が生じた場合のみlet
を使うという方針が推奨されています。オブジェクトや配列の場合でもconst
で宣言可能ですが、その場合は参照自体を変更できないだけで、中身の要素やプロパティは変更できます。
- 定数や固定値を保持したい場合
- 意図せぬ再代入を防ぎたい場合
- コードの可読性・保守性を高めたい場合
特にモダンなJavaScriptの書き方では「まずconst
を使い、必要に応じてlet
に切り替える」というルールが広く採用されています。これにより、予期せぬ副作用を減らし、安全で安定したコードを実現できます。
constを使うべきケース
値を固定したい定数宣言
JavaScriptで定義した変数は、基本的に後から値を変更できる場合があります。しかし、計算に用いる定数や設定値のように、意図的に値を固定したいケースではconst
による宣言が最適です。例えば、円周率やアプリケーションのバージョン番号、システム上で変更してはいけないフラグなどをconst
で宣言しておけば、プログラムの健全性を維持できます。
「値を一度決めたら変更しない」ことを明示できるため、開発者同士の共通認識を持つ上でも有効です。これにより、チーム開発における不意な変更や誤った代入によるバグ発生を防ぐ効果があります。
意図しない再代入を避けたい場合
複雑なコードでは、変数がどのタイミングで再代入されているのかを追いかけるのが困難になることがあります。特に大規模な開発や長期的な改修においては、「知らないうちに別の箇所で値が書き換えられていた」というリスクが生じます。const
を利用すれば、値が固定されるため、意図しない再代入を防ぎデバッグの工数を大幅に減らすことができます。
このように、安全性の高いコード設計を行いたい場合に、const
は極めて有効です。特に、外部から受け取った値をそのまま処理に利用する場面や、変更されるべきでない初期設定関連の情報を保持する際に適しています。
可読性と保守性の向上
コードの可読性を高めることは、プログラマーにとって非常に重要です。const
を使用することで、「この値は変わらない」という意図をコードの中に明確に示すことができます。読み手は変数名を見るだけで、値が動的に変化するのか、固定されたものなのかを理解できるため、理解コストを下げられます。
また、保守性の観点でもconst
は有効です。将来的にコードを見直す時、const
で宣言されている部分は「固定値」として安心して参照できるため、コードリファクタリングをスムーズに進められます。結果的にバグの発生を抑え、システム全体の品質向上に寄与します。
- 固定値であることが明確になる
- チーム開発での安心感が増す
- 誤った再代入を防止できる
- 保守・改修時の理解が容易になる
実用的なコード例
基本的な定数の宣言例
JavaScriptで定数を宣言する際には、const
を用いるのが一般的です。これは値を再代入させない保証があるため、意図しない変更を避けられます。特にアプリケーション内で絶対に変更されない値(固定のAPIエンドポイントや計算に用いる数値定数など)に適しています。
// 基本的な定数の宣言例
const API_URL = "https://example.com/api";
const TAX_RATE = 0.1;
console.log(API_URL); // "https://example.com/api"
console.log(TAX_RATE); // 0.1
このように、定数として意味を持つ値をconst
で定義することで、プログラムの可読性と安全性が向上します。
配列やオブジェクトでの利用例
const
で配列やオブジェクトを宣言した場合、変数そのものの再代入はできませんが、内部の要素やプロパティを変更することは可能です。この特性を知っていると、柔軟にデータを取り扱えます。
// 配列のconst利用例
const fruits = ["apple", "banana"];
fruits.push("orange"); // 要素追加は可能
console.log(fruits); // ["apple", "banana", "orange"]
// オブジェクトのconst利用例
const user = { name: "Taro", age: 25 };
user.age = 26; // プロパティ変更は可能
console.log(user); // { name: "Taro", age: 26 }
配列やオブジェクトを扱う場合でもconst
を活用することで、変数の参照先が変わらないという安全性を確保しつつ、柔軟にデータを更新できます。
条件分岐やループ内での利用例
const
はブロックスコープを持つため、条件分岐やループの中で一時的に使用する変数を宣言するケースでも便利です。スコープ外に影響を及ぼさないため、予期せぬ値の上書きを防止できます。
// if文での利用例
if (true) {
const message = "条件に一致しました";
console.log(message);
}
// console.log(message); // エラーになる(スコープ外)
// ループでの利用例
const numbers = [1, 2, 3];
for (const num of numbers) {
console.log(num);
}
// ループごとにnumは新しい定数として扱われる
このように条件分岐やループ内でconst
を使うと、コードの見通しが良くなり、意図しない変数共有を回避できます。特に複数人で開発するプロジェクトでは、エラーの温床を減らすために積極的に導入されるべき書き方です。
constを中心にしたモダンJavaScriptの書き方
開発における推奨スタイル
モダンなJavaScript開発では、変数宣言においてはまず const
を優先的に使用することが推奨されています。理由は、変数の再代入を防ぐことで予期せぬ動作やバグを減らし、より堅牢でメンテナンス性の高いコードを書くことが可能になるからです。
特に大規模な開発やチームでのコラボレーションにおいて、var
のようにスコープが不明確な宣言方法を避け、let
と const
を適切に使い分けることが主流になっています。その中でも、const
をデフォルトとして用いることで、開発の初期段階から「不変であるべき値」と「変更の可能性がある値」を明確に区別できるメリットがあります。
推奨されるコーディングスタイルは以下のとおりです。
const
をデフォルトとし、不変な値を明確化する- 再代入の必要がある場合のみ
let
を使用する - スコープを意識し、意図せずグローバル変数が生成されないようにする
- 配列やオブジェクトも
const
で定義し、参照の不変性を優先する
このようなスタイルを守ることで、コードレビューやリファクタリングが容易になり、チーム全体で統一された記述が担保されます。特にESLintなどの静的解析ツールを併用すれば、「再代入不要な変数は const を使うべき」といったルールを自動的に適用できるため、開発効率の向上にもつながります。
まとめ
constのメリットと注意点の整理
JavaScriptにおいてconstは「再代入を禁止する変数宣言方法」として非常に有用です。コードの意図を明示し、予期せぬ値の変更を防ぐことで、バグの発生率を下げる役割を果たします。特に、大規模なアプリケーションやチーム開発においては「値の固定化による安全性の担保」が大きなメリットとなります。
ただし、注意点として「constで宣言したオブジェクトや配列は、参照先そのものは変更不可ですが、中身の要素は変更可能」である点を理解しておく必要があります。この性質を誤解すると、意図しない挙動につながりかねません。つまり、constは完全な「不変性」を保証するわけではないため、利用時にはデータ構造の性質を正しく把握しておくことが重要です。
- メリット: 再代入不可、コードの意図が明確、可読性・保守性の向上
- 注意点: 配列やオブジェクトの「内容」は変更可能、不変性を保証しない
letとの適切な使い分けの指針
JavaScriptでの変数宣言においては、「まずconstを使い、必要な場合に限りletを使う」という方針が推奨されます。これはモダンな開発スタイルにおける一般的なベストプラクティスであり、意図的な再代入が伴う処理にのみletを使うことで、より安全かつ予測可能なコードが書けるようになります。
具体的には次のような指針が考えられます。
- constを優先: 値が固定される変数や、再代入の必要がない場合には迷わずconstを選ぶ。
- letは例外的に使用: ループカウンタなど、再代入がコードの本質であるケースに限って利用する。
- varは避ける: 古い書き方でありスコープ管理に難があるため、let/constの利用が基本。
このように「デフォルトはconst」という基本姿勢を徹底することで、不要なリスクを避けつつ、コードの明確さを保つことができます。結果として、開発効率や保守性の高いJavaScriptコードが実現できるでしょう。