プログラミングを行う際に、非常によく使われる手法として変数宣言があります。

例えば、「この箱には、12という数値を入れる」「あの箱には、”JavaScript”という文字列を入れる」など、変数の名前(箱)と、変数に格納されるデータ(文字列や数値など)を決められるのが変数宣言です。

宣言された変数は、繰り返し使える利便性があり、計算式や関数を作る場面で活躍します。

JavaScriptでは、letとconstを使って変数宣言を行いますが、どちらを使うべきかシチュエーションに悩む方も少なくないのではないでしょうか。
今回はletとconstをうまく使い分けられるように、性質やスコープとの関係性について紹介していきます。

「var」とは

letとconstの性質を説明する前に、「var」という変数について少し補足します。

プログラミング言語が時代とともに進化していくように、JavaScriptもバージョンが更新されていきます。現在最新版として使われているのが、「ES6(ECMAScript6)」というバージョンです。

以前までは変数宣言にvarのみを使用していましたが、ES6の環境から「let」と「const」が新たに追加されました。
varはスコープの範囲を広げる自由度の高い変数のため、意図していないエラーが起こり得ることから、使用頻度は低いです。特別な意図がない限りはletとconstを使うようにしましょう。

let, const, varには、以下のような特徴があります。

let const var
再代入
再宣言
ブロックスコープ
関数スコープ

letとconstの使いかた

ここからはletとconstを取り扱っていきます。

変数の宣言方法

letとconstの宣言方法に違いはなく、文字列や数字、配列などを格納することができます。

//let
let number = 1;
let string = 'letの場合';
let array = [a, b, c];
let object = {id: 1, name: 'yamada'};

console.log(number); //1
console.log(string); //letの場合
console.log(array[2]); //c
console.log(object.name); //yamada

//const
const number = 50;
const string = 'constの場合';
const array = [x, y, z];
const object = {color: 'yellow', price: 500};

console.log(number); //50
console.log(string); //constの場合
console.log(array[0]); //x
console.log(object.price); //500

値の参照が必要な場合や、他の関数に再利用するときなどに使われます。

再代入

一度宣言した変数を更新することを再代入といいます。
letは値の再代入ができる一方で、constはできません。

letの場合

let a = 1; //変数宣言
a = 10; //再代入
console.log(a); //10

constの場合

const b = 1; //変数宣言
b = 10; //再代入
console.log(b); // Assignment to constant variable.

変数を再代入するケースはあまり多くありませんが、ループ処理などの変数の数値が変わるような場合などに、letを用いて再代入をすることがあります。例えば、ボタンをクリックするごとに、回数をカウントし、カウント数値を保持する必要がある場合などに、letが役に立ちます。

再宣言

一度宣言した変数を、同じ変数名を使って再び宣言をし直すことを再宣言と言います。
letとconstどちらも2回以上宣言することはできません。

letの場合

let a = 1; //変数宣言
let a = 10; //再宣言
console.log(a); // SyntaxError: Identifier 'a' has already been declared

constの場合

const b = 1; //変数宣言
const b = 10; //再宣言
console.log(b); // SyntaxError: Identifier 'b' has already been declared

プログラムが長くなってくると、誤って同じ変数名をつけてしまうことがあるかもしれません。再宣言ができないメリットとして、このように別用途の変数に同じ変数名をつけてしまうことを防ぐことができます。

スコープについて

ここからは変数とスコープの関係性について説明していきます。

スコープとは?

「スコープ」とは、変数や関数の有効範囲のことです。通常、ある変数の有効範囲外からアクセスしようとしても、その変数にアクセスすることができません。スコープを意識することで、予期せぬ不具合を防ぎ、より安全なプログラムを書くことができます。

スコープには「グローバルスコープ」と「ローカルスコープ」の2種類が存在します。

グローバルスコープ

プログラムのどこからでもアクセスできる範囲のことをグローバルスコープと言います。プログラムの一番外側すなわちトップで宣言されたlet, const, varいずれかの変数は、グローバスコープを持ち、グローバルスコープを持つ変数のことをグローバル変数と言います。

let a = 1;

console.log(a); //1
function global() { 
  console.log(a); // 1
}
global(); 

トップ直下からのアクセスや関数内からのアクセスができるように、一番外側で宣言した変数aは、グローバルスコープを持ち、あらゆる場所からアクセスを許します。

ローカルスコープ

プログラムの特定の範囲内でアクセスを許可する変数のことをローカル変数と呼び、その変数が持つ有効範囲のことをローカルスコープと呼びます。
ローカルスコープは、「ブロックスコープ」と「関数スコープ」の2種類に分類されています。

ブロックスコープ

ブロックスコープとは、ブロック{}ごとに囲まれた範囲のことです。
ブロック内でletやconstで宣言された変数は、ブロックスコープを作り、ブロックスコープ外からのアクセスを制限します。

一方、varで宣言された変数は、ブロックスコープを持つことはできません。そのため、外からのアクセスを許可します。

{
 let a = 1;
 const b = 10;
 var c = 100;
}

console.log(a); //ReferenceError: a is not defined
console.log(b); //ReferenceError: b is not defined
console.log(c); //100

letとconstはブロックスコープを作るためエラーが返ってきますが、varの場合は、ブロックスコープを作ることができないため、値を参照することができます。
varで宣言された変数は、自由度が高く一見便利そうにも思えますが、どこからでもアクセスすることができ、意図せずに値を変更してしまう恐れがあるため、注意が必要です。

関数スコープ

関数スコープとは、関数のブロック{}ごとに作られる範囲のことです。
関数スコープ内でlet、const、varのいずれかで宣言された変数は、関数スコープの外からはアクセスできません。

function scope() {
 let a = 1;
 const b = 10;
 var c = 100;

 a = 2; //再代入 

 console.log(a); //2
 console.log(b); //10
 console.log(c); //100
}
scope();

console.log(a); //ReferenceError: a is not defined
console.log(b); //ReferenceError: b is not defined
console.log(c); //ReferenceError: c is not defined

関数のブロック内で変数にアクセスしたものは、それぞれ値を参照することができますが、関数のブロック外からはアクセスできないため、エラーとなり、値を参照できないことがわかります。

letとconstどちらを使うべきか?

基本的にはconstを使うことをおすすめします。再代入や再宣言ができず制約が多いからこそ、意図しない挙動を防ぐことができるからです。

constでは実装できない変数の再代入が必要なときはletを使用しましょう。以下は、letを使うべき場合の具体例です。例えばfor文のイテレータにはletを使います。

for (let i = 0; i < 3; i++) {
console.log(i);
}

まとめ

今回は変数の特徴やスコープとの関係性について解説しました。

変数の扱いかたや必要性を意識することが、安全でわかりやすいコードを書くためのポイントです。これを機にletやconstの使い方をマスターしていきましょう。