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の簡単な動作確認は開発者ツールが最強!