質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

8回答

39649閲覧

JavaScript: const の配列の値が変えられるのはなぜ?

Nippun

総合スコア1147

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

5グッド

8クリップ

投稿2018/04/10 04:04

const の配列の値が変えられるのはなぜでしょうか?

JavaScript

1const list = []; 2list.push(3); 3list.push(44); 4list[0] += 1; 5console.log(list);

こうすると結果は[ 4, 44 ]となります。
Constと定義しているのになぜ配列の中身が変更されるのでしょうか?
また、そもそもなぜPushできるのでしょうか?

xxxtentacion, miyabi_pudding, yamaki, defghi1977, yohhoy👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答8

0

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

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/const

Object.freeze()

Object.freeze()を使えば、配列やオブジェクトを不変に出来ますが、以下のデモコードの通り、ネストされている場合は可変のままになります。

配列

// #1 const list1 = [] list1.push(1); console.log(list1); //[ 1 ] // #2 const list2 = []; Object.freeze(list2); //list2.push(2); //TypeError: Can't add property 0, object is not extensible // #3 const list3 = [[]]; Object.freeze(list3); list3[0].push(3); console.log(list3); // [ [ 3 ] ]

## オブジェクト

// #1 const obj1 = { id: 1 } obj1.id = 2; console.log(obj1.id); //2 // #2 const obj2 = { id: 10 } Object.freeze(obj2); obj2.id = 20; console.log(obj2.id); //10 // #3 const obj3 = { id: 100, items: { id: 1000 } } Object.freeze(obj3); obj3.items.id = 2000; console.log(obj3.items.id); //2000

投稿2018/04/10 04:12

編集2018/04/10 04:24
HayatoKamono

総合スコア2415

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

defghi1977

2018/04/10 04:26

エラーにしたい場合はどうすりゃいいんでしょうね? Proxyでラップしてsetされたらthrow Errorとかかな
HayatoKamono

2018/04/10 04:27

それですね!まさにその方法を紹介している記事を以前読んだことがあります。
guest

0

それは配列の中身を変えているからですよ. もちろん, 配列そのものを交換する(変数listへの代入)はエラーとなります.

const list = []; list = [];//エラー

投稿2018/04/10 04:11

defghi1977

総合スコア4756

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

JavaScript > リファレンス > 文と宣言 > const

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

ES6のconstを使い倒すレシピ1 - 前提共有編 〜 JSおくのほそ道 #034

constの盲点

ではconst化すれば、あらゆる値の状態変化がないことを保証できるかというと、そうではありません。
const宣言の挙動としては**「再代入を許容しない」**ことにあります。再代入以外は許容します。

とのことです。

投稿2018/04/10 04:12

can110

総合スコア38339

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

const は再代入不可

既出の回答通り、const は再代入不可にするだけであり、改変は可能です。
詳細は出尽くしている為、割愛します。

Object.freeze()

こちらが本題。
HayatoKamono さんの回答に対し、defghi1977 さんが次のコメントを残しています。

エラーにしたい場合はどうすりゃいいんでしょうね? Proxyでラップしてsetされたらthrow Errorとかかな

プロパティの変更はエラーになりませんが、追加はエラーになるので再帰的にオブジェクトを freeze する事で影響範囲を広げる事は出来ます。

しかし、Object.freeze はプロパティ変更に対しては不変であってもエラーを発生させません。
ここで、[[Prototype]] 上のプロパティと直属のプロパティが別管轄である事に注目します。

JavaScript

1var object = Object.create({a:{b:{c:{d:{e:true}}}}}); 2 3deepFreezeFromObject(Object.getPrototypeOf(object)); // [[Prototype]] を freeze 4deepFreezeFromObject(object); // 直属を freeze 5object.a = 1; // TypeError: Cannot assign to read only property 'a' of object '#<Object>'

object.a は存在しないのでプロパティ追加扱いになるというロジックです。
が、[[Prototype]] を辿ってプロパティ改変を試みれば、TypeErrorにならずに不変である事象に変わりはないので、ネタにしかならないですね…。

JavaScript

1Object.getPrototypeOf(object).a = 2; // エラーにならない 2console.log(object.a); // {b:{c:{d:{e:true}}}}

Re: Nippun さん

投稿2018/04/10 13:09

think49

総合スコア18189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

defghi1977

2018/04/10 19:57

プロトタイプチェーンの思考題材として良い記事
guest

0

constはあくまで、再代入が不可能になるだけです。オブジェクトの中の各要素までは保護されていません。
このページの例にあるように、配列にpushすることも普通にできます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/const

投稿2018/04/10 04:12

Udomomo

総合スコア1524

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Array オブジェクトはミュータブル(変更可能)だからです。

js

1var a = 1; 2var b = a; 3a = 2; 4a === b; // false 5 6var a = [1]; 7var b = a; 8a[0] = 2; 9a === b; // true

ミュータブルな型とイミュータブルな型の相違を知ろう - Qiita

投稿2018/04/10 04:16

Lhankor_Mhy

総合スコア36898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

JavaScriptはオブジェクトについて参照渡しだなんて、信じない

今回の質問はこれが分かりやすいと感じました。
JavaScriptはオブジェクトや、それから派生して作られた配列等は
メモリ空間上に配列がポコンと作られ、list変数にメモリ空間上のアドレス値が格納されます。

JavaScript

1console.log([] === []) // false

この結果がfalseになるのは、2つの配列をメモリ空間上に生成してアドレス値同士で比較したからです。
だから違うものとしてfalseが帰ってきます。

constが見張り続けるのはこのメモリ空間上のアドレス値です。
その中にあるメモリ空間内の実体に関しては知らないというスタンスです。

でもまぁ、list.push(hoge)みたいなので変更しまくる場合、心情的にはletを使いたくなりますね。
eslint等ではlist.pushを使いまくったからといって再代入はしていない為、不要なletを許してくれず、constで宣言しろと怒られます。

投稿2018/04/10 04:35

miyabi-sun

総合スコア21194

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

javascriptのconstは、再代入が出来ない(一旦値が入れられたら、後で変えることができない)という意味です。
数字や文字列のようなリテラルだけでなく、質問のコードのように配列を代入することも可能です。

質問のコードで、listの値は、1つの配列(配列への参照)から変わってはいません。

そして、listから参照されているのは配列なので、値を変更したりpushやpopなど、配列で出来る事は何でもできます(配列なのですから)

投稿2018/04/10 04:31

coco_bauer

総合スコア6915

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問