Warum kann ich den Wert einer Konstanten in Javascript ändern?

101

Ich weiß, dass ES6 noch nicht standardisiert ist, aber viele Browser unterstützen derzeit const Schlüsselwörter in JS.

In der Spezifikation steht geschrieben, dass:

Der Wert einer Konstante kann sich durch Neuzuweisung nicht ändern, und eine Konstante kann nicht erneut deklariert werden. Obwohl es möglich ist, eine Konstante zu deklarieren, ohne sie zu initialisieren, wäre dies aus diesem Grund nutzlos.

und wenn ich so etwas mache:

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

Ich sehe , dass alles in Ordnung ist xxximmer noch 6und yyyist [].

In diesem Fall yyy.push(6); yyy.push(1);wurde mein konstantes Array geändert. Im Moment ist es so [6, 1]und übrigens kann ich es immer noch nicht ändern yyy = 1;.

Ich das ein Fehler, oder vermisse ich etwas? Ich habe es in der neuesten Chrom und FF29 versucht

Salvador Dali
quelle
1
Können Sie einfach eine Klasse erstellen, die Variable deklarieren und ihren Wert innerhalb der Klasse zuweisen? Erstellen Sie dann einen GETTER für diese Variable. und implementieren Sie keinen Setter. Es sollte eine Konstante implementieren ...
Andrew
8
@ Andrew danke, aber ich frage nicht, wie ich das machen kann. Ich bin gespannt, warum sich das Schlüsselwort const so verhält.
Salvador Dali

Antworten:

171

In der Dokumentation heißt es:

... Konstante kann sich durch Neuzuweisung nicht ändern
... Konstante kann nicht neu deklariert werden

Wenn Sie einem Array oder Objekt etwas hinzufügen, das Sie nicht neu zuweisen oder deklarieren, wird die Konstante bereits deklariert und zugewiesen. Sie fügen lediglich die "Liste" hinzu, auf die die Konstante zeigt.

Das funktioniert also gut:

const x = {};

x.foo = 'bar';

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

x.foo = 'bar2';

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

und das:

const y = [];

y.push('foo');

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

y.unshift("foo2");

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

y.pop();

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

aber keines von diesen:

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
Adeneo
quelle
4
Sie meinen also, dass dies kein Fehler ist, aber es sollte so funktionieren? Weil ich dachte, dass die Idee der Konstante ist, dass sie nicht geändert werden kann. Grundsätzlich hat ein Programmierer das Vertrauen, dass nichts den Wert innerhalb meiner Konstante ändern kann, egal was passieren wird.
Salvador Dali
2
Ich denke, es ist nicht so einfach. In diesem Fall ist der Wert der Konstante ein Array spezifischer Elemente. Wenn Sie etwas ändern, ändern Sie den Wert .
Veritas
6
Ja, es soll so funktionieren, Sie weisen die Konstante nicht neu zu, es ist immer noch dieselbe Referenz, Sie fügen dem Array nur die Konstantenreferenzen hinzu, und Arrays und Objekte sind wie "Listen", wenn Sie sie ändern Ändern Sie die Referenz nicht und deklarieren Sie die Konstante nicht erneut.
Adeneo
26
@SalvadorDali: Konstante und schreibgeschützt sind zwei verschiedene Dinge. Ihre Variable ist konstant , aber das Array, auf das sie zeigt, ist nicht schreibgeschützt
Matt Burland
43

Dies geschieht, weil Ihre Konstante tatsächlich einen Verweis auf das Array speichert . Wenn Sie etwas in Ihr Array einfügen, ändern Sie nicht Ihren konstanten Wert, sondern das Array, auf das es zeigt. Das gleiche würde passieren, wenn Sie einer Konstante ein Objekt zuweisen und versuchen, eine Eigenschaft davon zu ändern.

Wenn Sie ein Array oder Objekt einfrieren möchten, damit es nicht geändert werden kann, können Sie die Object.freezeMethode verwenden, die bereits Teil von ECMAScript 5 ist.

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]
Guilherme Sehn
quelle
1
Nach derselben Logik hat eine fiveauf 5 gesetzte Konstante nicht den Wert 5, sondern nur einen Verweis auf die Zahl 5. Wenn ich das tue, five++ändere ich nicht die Konstante, sondern nur die Zahl, auf die sie zeigt.
Anthony
3
@Anthony die Referenzsache funktioniert nur für Arrays und Objekte, nicht für primitive Werte
Guilherme Sehn
1
@Anthony In Ihrem Beispiel ändern Sie die Nummer, auf die die Variable fivezeigt (die Variable war fivefrüher eine Bezeichnung für die Nummer 5, jetzt zeigt sie auf eine andere Nummer: 6). Verweist im Beispiel in der Frage (und dieser Antwort) ximmer auf dieselbe Liste. Wenn xes sich um const handelt, können Sie nicht auf eine andere Liste verweisen. Der einzige Unterschied besteht darin, dass dieselbe Liste wachsen oder schrumpfen kann. Dies ist nur für Arrays und Objekte möglich und nicht für Grundelemente.
ShreevatsaR
9

Dies ist ein konsistentes Verhalten mit jeder Programmiersprache, die mir einfällt.

Betrachten Sie C - Arrays sind nur verherrlichte Zeiger. Ein konstantes Array bedeutet nur, dass sich der Wert des Zeigers nicht ändert - aber tatsächlich sind die an dieser Adresse enthaltenen Daten frei für.

In Javascript dürfen Sie Methoden für konstante Objekte aufrufen (natürlich - sonst würden konstante Objekte nicht viel Sinn machen!). Diese Methoden können den Nebeneffekt haben, das Objekt zu ändern. Da Arrays in Javascript Objekte sind, gilt dieses Verhalten auch für sie.

Sie können sich nur darauf verlassen, dass die Konstante immer auf dasselbe Objekt zeigt. Die Eigenschaften des Objekts selbst können sich frei ändern.

Donnerstag
quelle
4

Die const-Deklaration erstellt einen schreibgeschützten Verweis auf einen Wert. Dies bedeutet nicht, dass der darin enthaltene Wert unveränderlich ist, sondern dass die Variablenkennung nicht neu zugewiesen werden kann. Wenn der Inhalt beispielsweise ein Objekt ist, bedeutet dies, dass der Inhalt des Objekts (z. B. seine Parameter) geändert werden kann.

Ein weiterer wichtiger Hinweis:

Globale Konstanten werden nicht zu Eigenschaften des Fensterobjekts ...

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

Benjamin West
quelle
3

Ich denke, dies würde Ihnen mehr Klarheit in Bezug auf das Problem geben: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 .

Im Grunde läuft es darauf hinaus, constimmer auf dieselbe Adresse im Speicher zu zeigen. Sie können den in dieser Adresse gespeicherten Wert ändern, aber auch nicht die Adresse, auf die auch gezeigt constwird.

Die von constIhnen erwähnte Definition gilt, wenn die constauf eine Adresse zeigt, die einen primitiven Wert enthält. Dies liegt daran, dass Sie diesem Wert keinen Wert zuweisen können, constohne seine Adresse zu ändern (da das Zuweisen primitiver Werte auf diese Weise funktioniert) und das Ändern der Adresse von a constnicht zulässig ist.

Wenn der constWert auf einen nicht primitiven Wert zeigt, kann der Wert der Adresse bearbeitet werden.

Zyxmn
quelle
1

Kam durch diesen Artikel, als ich suchte, warum ich ein Objekt aktualisieren konnte, obwohl ich es als definiert hatte const. Der Punkt hier ist also, dass nicht das Objekt direkt, sondern die darin enthaltenen Attribute aktualisiert werden können.

Zum Beispiel sieht mein Objekt so aus:

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

Die obigen Antworten haben richtig darauf hingewiesen, dass es das Objekt ist, das const ist und nicht sein Attribut. Daher kann ich die ID oder den Namen folgendermaßen aktualisieren:

number.name = 'John';

Ich kann das Objekt jedoch nicht wie folgt aktualisieren:

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

TypeError: Assignment to constant variable.
Atul O Holic
quelle
1
Ihr Beispiel ist eine praktische und korrekte Beschreibung
Ebrahim
0

Da Sie in const die Werte eines Objekts ändern können, speichert das Objekt die Zuordnungsdaten nicht tatsächlich, sondern zeigt darauf. Daher gibt es in Javascript einen Unterschied zwischen Grundelementen und Objekten.


quelle