プログラミング

JavaScriptのAssignment to constant variableを直す方法|constとletの選び方

constへの再代入で出るTypeErrorを、カウンター・計算・配列の例で解説。letへ変える場合と、constを保って直す場合の判断、練習問題と模範解答を紹介します。

数を1増やしたいだけなのに、TypeError: Assignment to constant variable.で止まる。「計算式は合っていそうなのに」と悩んだら、計算結果を入れ直そうとした変数の宣言を見ます。

constで宣言した名前には、後から別の値を再代入できません。値が変わるカウンターならletへ直しますが、全部のconstを置き換える必要はありません。この記事では、エラーが出た場所から使い分けを考えます。

変数や代入の意味から確認したい場合は、JavaScriptの変数・型・計算が前提になります。

まずエラーが出る短い例を見る

次は、数を1増やして表示するつもりのコードです。

const count = 0;
count += 1;
console.log(count);

count += 1で、新しい値をcountへ入れ直そうとして止まります。ChromeやNode.jsでは、次のようなエラーになります。Firefoxなどでは文言が異なります。MDN:constへの無効な代入

TypeError: Assignment to constant variable.

+= 1は、この数値の例ではcount = count + 1と同じ計算です。右側で1を求めることはできても、左側のcountへ再代入できません。その後のconsole.logまで進まないので、数字が出ないのも同じ原因です。

値を変える予定ならletを使う

カウンターは、0、1、2と変化する値です。宣言をletへ直します。

let count = 0;
count += 1;
console.log(count); // 1

宣言は名前を作ること、代入は値をその名前へ結び付けることです。宣言した後で値を入れ直す操作を、再代入と呼びます。

宣言 再代入 今回の使いどころ
const できない 途中で入れ替えない値
let できる 回数や残り時間など、変わる値

count++やcount -= 1も、countの値を更新します。=だけを検索しても見逃すので、エラー行の名前を確かめ、宣言した場所まで戻ってください。

constのまま、計算の組み立てを直せる場合もある

次は商品の合計に送料を足す例です。

const total = 500 * 3;
total = total + 100; // 再代入でエラー

最終結果だけが欲しいなら、途中の金額と送料込みの金額を別の名前にできます。

const price = 500;
const quantity = 3;
const shipping = 100;
const subtotal = price * quantity;
const total = subtotal + shipping;

console.log(total); // 1600

subtotalは商品だけの小計、totalは送料を含む合計です。どちらも再代入していません。計算の意味も読みやすくなりました。

反対に、ボタンを押すたびに数量を変えるなら、その数量にはletが合います。「この値は途中で変わるか」「別の意味の結果を同じ名前へ入れていないか」で判断してみてください。

constの配列は、なぜpushできるのか

ここが少しややこしいところです。次の配列への追加はできます。

const items = ["ノート", "ペン"];
items.push("付せん");
console.log(items.length); // 3

constが固定するのは、名前と値の結び付きです。itemsが同じ配列を参照したまま、その配列の要素を変更することまでは禁止しません。参照は、ここでは「どの配列を使っているかを示すもの」と考えてください。MDN:const

一方、別の配列への入れ替えは再代入です。

const items = ["ノート", "ペン"];
items = ["付せん"]; // エラー

オブジェクトも同じです。

const player = { name: "Aoi", score: 0 };
player.score = 10; // 同じオブジェクトの項目を変更
console.log(player.score); // 10

player = { name: "Aoi", score: 10 };と書けば、今度は別のオブジェクトへの再代入になります。配列やオブジェクトを完全に変更禁止にしたい場合は、constだけでは足りません。

よく似た別のエラーを区別する

コンソールで何度もコードを試すと、別のエラーが混ざることがあります。

コードや状況 問題
const count = 0; count = 1; 再代入によるTypeError
同じスコープでconst countをもう一度宣言 再宣言によるSyntaxError
普通の宣言でconst count;とだけ書く 初期値がなくSyntaxError

スコープは、同じ名前を参照できる範囲です。例えば{ ... }で囲んだブロックは、その範囲を作ります。同名の別変数がある大きなコードでは、エラー行から見える方の宣言を確認します。

練習コードは1例ずつ別に実行してください。コンソールに前の宣言が残って混乱したら、ページを再読み込みしてから試すと整理できます。letへ変えれば何でも直る、とは覚えない方が後で助かります。

練習:変わる値だけをletにする

次のコードを、10点加算して表示できるように直してください。プレイヤー名は途中で変更しません。あわせて、最後の配列への追加も直す必要があるか考えます。

const playerName = "Aoi";
const score = 0;
const results = [];

score += 10;
results.push(score);
console.log(`${playerName}: ${score}点`);

模範解答

const playerName = "Aoi";
let score = 0;
const results = [];

score += 10;
results.push(score);
console.log(`${playerName}: ${score}点`);
console.log(results.length);
Aoi: 10点
1

解説

再代入するのはscoreなので、その宣言をletへ変えます。playerNameは変わらず、results.push(score)は同じ配列への追加なので、残り2つはconstのままです。

エラーが消えたら、期待する点数と配列の要素数も確かめます。「止まらなくなった」と「欲しい結果になった」の両方を見る習慣を付けましょう。

続けて読む

← 記事一覧へ戻る