constの扱いを見直す

ある案件中にちょっとした気づいたことを記述いこうと思います。

constの扱い方

ES6から導入されたlet, constですが、使い方・認識が間違っていました。

再宣言はできない

これは当たり前ですよね。

let hoge = 100;
let hoge = 200;

// Uncaught SyntaxError: Identifier 'hoge' has already been declared
// 再宣言しようとするとエラーが発生。constでも同様

constの場合は再代入ができない

const piyo = 100;
piyo = 200;

// Assignment to constant variable.
// 再代入しようとするとエラーが発生

再代入できないのは分かった。んじゃ、配列やオブジェクトも?

配列の場合

const huga = [100];
huga.push(200)

console.log(huga)
// [100, 200]
// あれ、変更できるや〜ん

オブジェクトの場合

const moge = {x: 100};
moge.y = 200

console.log(moge)
// {x: 100, y: 200}
// あれ、追加されてるや〜ん

注目すべきは再代入はできないが。。。

注目すべきは再代入はできないが、不変ではないということ。 const - JavaScript | MDN

const 宣言は、値への読み取り専用の参照を作ります。その値が不変ということではなく、その変数識別子が再代入できないというだけです。たとえば、定数がオブジェクトのコンテンツの場合、オブジェクトのコンテンツ(例 その引数)自体は変更可能です。

MDNのリファレンスにもちゃんと書いてありました。しかも、『不変ということではなく』の「なく」が太文字になっていました。。。

オブジェクト・配列を不変なものにするには

オブジェクトの場合

Object.freeze()を使うこと不変なオブジェクトに変更することが可能のようです。

const foo = {x: 100, y: 200};
Object.freeze(foo);
foo.z = 300;
console.log(foo)
// {x: 100, y: 200}
// おぉ、追加されていない

配列の場合

JavaScriptでconstの配列の値が変わる理由と変更しない方法 | iwb.jp こちらのサイトさんによると不変なオブジェクトにしてから、配列にすることで不変な配列にすることが可能のようです。 ちなみに上記のサイトさんで開発者ツールを開くとおもしろいメッセージが表示されました。気になる人は確認してみてください。

const bar = [100, 200, 300];
const arrObj = bar.reduce(
  (a, c, i) => Object.assign(a, {[i]: c}), {}
);
Object.freeze(arrObj);
arrObj.hoge = 400;
console.log(Object.values(arrObj));
// [100, 200, 300]
// おぉ、配列でも変更されていない

まとめ

  • constは再代入不可だが、不変ではない
  • Object.freezeを活用することでオブジェクト、配列を不変にすることが可能
  • jsの簡単な動作確認は開発者ツールが最強!

参考