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

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

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

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

JavaScript

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

解決済

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

Nippun
Nippun

総合スコア1147

Node.js

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

JavaScript

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

8回答

5グッド

8クリップ

33862閲覧

投稿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_takatsuk, yamaki, defghi1977, yohhoy👍を押しています

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答8

17

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

総合スコア2409

Lhankor_Mhy, miyabi_takatsuk, miyabi-sun, recal, takito, tkturbo, kei344, yambejp, Nippun, defghi1977, 他7名👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

defghi1977

2018/04/10 04:26

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

2018/04/10 04:27

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

9

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

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

投稿2018/04/10 04:11

defghi1977

総合スコア4756

Lhankor_Mhy, ifaoerij, kei344, yambejp, Nippun, m.ts10806, maisumakun, yasahhi👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

8

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

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

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

constの盲点

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

とのことです。

投稿2018/04/10 04:12

can110

総合スコア36225

Lhankor_Mhy, miyabi-sun, kei344, yambejp, Nippun, defghi1977, m.ts10806, _adamay👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

6

ベストアンサー

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

総合スコア18033

miyabi_takatsuk, miyabi-sun, kei344, yambejp, defghi1977👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

defghi1977

2018/04/10 19:57

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

6

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

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

投稿2018/04/10 04:12

Udomomo

総合スコア1524

Lhankor_Mhy, kei344, yambejp, Nippun, defghi1977, m.ts10806👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

5

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

総合スコア33631

kei344, yambejp, Nippun, defghi1977, m.ts10806👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

3

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

総合スコア21039

Lhankor_Mhy, kei344, Nippun👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

3

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

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

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

投稿2018/04/10 04:31

coco_bauer

総合スコア6909

Lhankor_Mhy, kei344, Nippun👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Node.js

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

JavaScript

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