JavaScriptで定数の値を変更できるのはなぜですか


101

ES6はまだ標準化されていないことを知っています が、現在多くのブラウザconstがJSのキーワードをサポートしています

仕様では、次のように書かれています。

定数の値は再割り当てによって変更できず、定数を再宣言することはできません。このため、初期化せずに定数を宣言することは可能ですが、そのようにしても意味がありません。

そして私がこのようなことをすると:

const xxx = 6;
xxx = 999;
xxx++;
const yyy = [];
yyy = 'string';
yyy = [15, 'a'];

私はそのすべてがOKであることがわかりxxx、まだされる6yyyあります[]

しかし、実行するyyy.push(6); yyy.push(1);と、定数配列が変更されています。現在のところ[6, 1]、私はまだそれを変更できませんyyy = 1;

これはバグですか、それとも何か不足していますか?最新のクロームとFF29で試してみました


1
クラスを作成し、変数を宣言して、その値をクラス内に割り当てることができますか?次に、その変数のGETTERを作成します。セッターを実装しないでください。定数を実装する必要があります...
Andrew

8
@Andrewありがとう、でも私はこれをどうやればいいのか尋ねていません。constキーワードがこのように動作する理由を知りたいです。
サルバドールダリ2014年

回答:


171

ドキュメントは述べています:

...定数は再割り当てによって変更できません
...定数は再宣言できません

配列またはオブジェクトに追加する場合、定数の再割り当てや再宣言は行われません。定数はすでに宣言および割り当てられており、定数が指す「リスト」に追加するだけです。

だからこれはうまくいきます:

const x = {};

x.foo = 'bar';

console.log(x); // {foo : 'bar'}

x.foo = 'bar2';

console.log(x); // {foo : 'bar2'}  

この:

const y = [];

y.push('foo');

console.log(y); // ['foo']

y.unshift("foo2");

console.log(y); // ['foo2', 'foo']

y.pop();

console.log(y); // ['foo2']

しかし、どちらも:

const x = {};
x = {foo: 'bar'}; // error - re-assigning

const y = ['foo'];
const y = ['bar']; // error - re-declaring

const foo = 'bar'; 
foo = 'bar2';       // error - can not re-assign
var foo = 'bar3';   // error - already declared
function foo() {};  // error - already declared

4
これはバグではありませんが、このように動作するはずですか?定数の考え方は変更できないと思っていたからです。基本的にプログラマーは、何が起こっても、定数内の値を変更することはできないと信じています。
サルバドールダリ2014年

2
簡単ではないと思います。この場合、定数の値は特定の要素の配列です。何かを変更することは、を変更することを意味します。
veritas 2014年

6
はい、それはこのように機能するはずです、あなたは定数を再割り当てしていません、それはまだ同じ参照です、あなたは単に配列への定数参照を追加しています、そして配列とオブジェクトは「リスト」のようなものです、それらを修正します参照を変更したり、定数を再宣言したりしないでください。
adeneo 2014年

26
@SalvadorDali:定数読み取り専用は2つの異なるものです。変数は定数ですが、それが指している配列は読み取り専用で
Matt Burland

43

これは、定数が実際に配列への参照を格納しているために発生します。配列に何かを結合すると、定数値を変更するのではなく、それが指す配列を変更します。オブジェクトを定数に割り当て、そのプロパティを変更しようとした場合も同様です。

変更できないように配列またはオブジェクトをフリーズする場合Object.freezeは、すでにECMAScript 5に含まれているメソッドを使用できます。

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]

1
同じロジックで、five5に設定された定数は実際には5の値を持たず、単に数値5への参照five++です。したがって、私が定数を変更しない場合は、定数が指す数値のみを変更します。
アンソニー

3
@Anthony参照は配列とオブジェクトに対してのみ機能し、プリミティブ値に対しては機能しません
Guilherme Sehn

1
@Anthonyあなたの例では、変数がfive指す数を変更しています(変数fiveは数5のラベルでしたが、今では別の数を指しています:6)。質問(およびこの回答)の例では、x常に同じリストを指しています。場合xのconstであるあなたはそれが別のリストを指すことはできません。唯一の違いは、同じリストが拡大または縮小できることです。これは、プリミティブではなく、配列とオブジェクトでのみ可能なことです。
ShreevatsaR

9

これは、考えられるすべてのプログラミング言語で一貫した動作です。

Cを検討してください-配列は単なる栄光のポインタです。定数配列は、ポインターの値が変化しないことを意味するだけですが、実際には、そのアドレスに含まれるデータは自由に使用できます。

JavaScriptでは、定数オブジェクトのメソッドを呼び出すことができます(もちろん、そうでない場合、定数オブジェクトはあまり目的に役立ちません!)これらのメソッドには、オブジェクトを変更する副作用があります。JavaScriptの配列はオブジェクトであるため、この動作はそれらにも適用されます。

あなたが確信しているのは、定数が常に同じオブジェクトを指すことです。オブジェクト自体のプロパティは自由に変更できます。


4

const宣言は、値への読み取り専用の参照を作成します。それが保持する値が不変であることを意味するのではなく、変数識別子を再度割り当てることができないということです。たとえば、コンテンツがオブジェクトである場合、これはオブジェクトのコンテンツ(たとえば、そのパラメーター)を変更できることを意味します。

さらに、重要な注意事項:

グローバル定数はウィンドウオブジェクトのプロパティにはなりません...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const


3

これで問題がより明確になると思います:https : //codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

基本的には、const常にメモリ内の同じアドレスを指していることになります。そのアドレスに格納されている値は変更できますが、ポイントしているアドレスも変更できませconstん。

constあなたが言及した定義はconst、がプリミティブ値を保持するアドレスを指している場合に当てはまります。これはconst、アドレスを変更せずに値を割り当てることができないためです(これはプリミティブ値の割り当てが機能する方法であるため)、aのアドレスの変更はconst許可されていません。

constが非プリミティブ値を指しているかのように、アドレスの値を編集することが可能です。


1

オブジェクトをとして定義した後でもオブジェクトを更新できた理由を検索しながら、この記事を読みましたconst。したがって、ここでのポイントは、直接オブジェクトではなく、更新可能なオブジェクトに含まれる属性であるということです。

たとえば、私のオブジェクトは次のようになります。

const number = {
    id:5,
    name:'Bob'
};

上記の答えは、constであり、その属性ではないオブジェクトであることを正しく指摘しました。したがって、次のようにしてIDまたは名前を更新できます。

number.name = 'John';

ただし、次のようにオブジェクト自体を更新することはできません。

number = {
    id:5,
    name:'John'
  };

TypeError: Assignment to constant variable.

1
あなたの例は実用的なもので正しい説明です
エブラヒム

0

constではオブジェクトの値を変更できるため、オブジェクトは実際には割り当てデータを格納せず、代わりにそれを指します。そのため、JavaScriptのプリミティブとオブジェクトには違いがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.