This question already has answers here:
Why can I change a constant object in javascript
(12 answers)
Closed 9 months ago.
In JavaScript:
const a = 6;
a = 2; // Error
const o = {};
o = 7; // Error
o.a = 5; // Good. Why?
const o = {a:1};
o.a = 2; // Good. Why?
I found people sometimes define a const object but later change its value. Why a const can be changed after its definition?
A variable declared with const means one thing: the standalone variable name cannot be reassigned with = later.
In contrast, o.a = 5; is not reassigning the variable name - it's mutating the content of the object, but it's not changing what the o variable points to in memory.
To prevent reassignment of a variable name, use const. To prevent mutation of an object is something entirely different - for that, you'd need something like Object.freeze or manipulate objects using immutable-js.
In the first case, a is const and cannot be reassigned. In the second and third, the object o is const so that object cannot be assigned another value, but its properties are not const. See here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in the case where the content is an object, this means the object's contents (e.g., its properties) can be altered.
const variables aren't enforced to be immutable.
From MDN:
Constants are block-scoped, much like variables defined using the let statement. The value of a constant can't be changed through reassignment, and it can't be redeclared.
Emphasis mine.
o.a = 5 isn't reassigning o; it's reassigning a property in o.
For adding more information from the other answers, if you want to define a constant object property. You can try these ways:
const o = {
get a() {
return 1;
}
};
o.a = 2;
// 1
console.log(o.a);
const o2 = {};
Object.defineProperty(o2, 'a', {
value: 1,
writable: false,
enumerable: true,
configurable: true
});
o2.a = 2;
// 1
console.log(o2.a);
Related
This question already has answers here:
Modifying a copy of a JavaScript object is causing the original object to change
(13 answers)
Closed 6 months ago.
var arr = []
var obj = {
a: undefined,
b: undefined,
c: undefined
}
var a = 0
while (a !== 100) {
arr.push(obj)
a++
}
var randNum
for (var i = 0; i < arr.length; i++) {
randNum = Math.floor(Math.random() * 2)
console.log(Math.floor(Math.random() * 2))
arr[i].a = Math.floor(Math.random() * 2)
arr[i].b = 5
}
console.log(arr)
When I console log arr, arr[n].a always equals one number, but thats not what I want, I want it to output a random number, like 0 or 1.
The issue is as VLAZ mentioned in their comment. To fully explore this, we need to understand reference vs. value types in JS.
Let's look at a simple program:
let a = 1;
let b = a;
a = 2;
console.log(b) // prints 1
This works because we're storing a simple, primitive type like a number. With more complex types like arrays and objects, we'll see different behavior.
let a = { foo: true, bar: true };
let b = a;
a.foo = false;
console.log(b) // prints { foo: false, bar: true }
This is because more complex types in JS like arrays and objects are passed by reference, not by value. In essence, this means that when we store an object using a variable, the variable is not storing the values, but rather a reference to the object's location in your machine's memory. Let's add comments to the above code for clarity.
// a stores a pointer to memory location A, where our object literal lives
let a = { foo: true, bar: true };
// b stores a pointer to memory location A
let b = a;
// change a value on the object in memory location A
a.foo = false;
// print the value in memory location A
console.log(b)
This reference vs value differentiation has to do with the complexities of managing memory when we have potentially large, dynamic objects, so JS does a bunch of low-level stuff for us behind the scenes and gives us a nice user-friendly syntax for instantiating a data type that would be more complicated to implement manually in a lower-level language. However, we still have to be aware of this difference.
The crux of your issue is that in each index of your array, you're storing a reference to the exact same object, so when you update one index, you're actually updating the value at the memory location the index is pointing to. Since all the indices are pointing to the same memory location, changing one behaves similarly to changing them all.
Fortunately, armed with this information we can simply devise a way to create a new object on each iteration, whether by copying the reference object or just passing an object literal to the Array.push() method. Here's a potential solution.
let arr = [];
for (let i = 0; i < 100; i++) {
// this "object literal" is defined when push is called, creating a new object on each iteration
arr.push({
a: Math.floor(Math.random() * 2),
b: 5,
c: undefined
});
}
This question already has answers here:
variable binding inside an object
(2 answers)
Closed 2 years ago.
While trying to understand how javaScript resolve variable, i wrote this code:
const a = 0;
var obj = {a: 1, foo: function(){console.log(a);}};
obj.foo();
I know that javaScript, like most of the programming languages, use the lexical/static scope to resolving variables.
But in this example, the lexical scope outside of foo function is obj scope and not global scope.
So why do i get output 0 instead of 1 ?
the lexical scope outside of foo function is obj scope and not global scope.
There is no such thing as "obj scope" or "object scope". In Javascript, every variable name (or identifier) is scoped to either a block (such as inside a loop, or inside a function block), or is global.
An object isn't a block. Putting a property on an object does not create a new identifier; referencing such a property name as if it were a standalone variable does not work, because it's not an identifier in scope.
The only time in which something like this would be possible would be if you used with and referenced the property as if it was a standalone variable inside the with block, but with should never be used.
const a = 0;
var obj = {
a: 1,
foo: function() {
console.log(a);
}
};
with (obj) {
console.log(a);
}
In an object with {a: 1} the 'a' is a string, not a variable. It does not assign 1 to 'a'. Instead it sets a key/value pair equivalent to { "a": 1 }.
It has nothing to do with scope. The variable a defined in the first line is the only variable of that name and never has its value changed in the code you gave.
Note also that you defined it as const meaning it cannot be assigned a different value.
If you need reference the a object property, is necessary use this.a, because a without this is the global variable.
const a = 0;
var obj = {a: 1, foo: function(){console.log(this.a);}};
obj.foo();
Because there is only one a, and it's declared on your first line.
In order to use this object's variables, you have to use this. For example:
const a = 0
var obj = { a: 1, foo: function() { console.log(this.a) } }
obj.foo(); // 1
When you use this.a, that's the same thing, if you use obj.a outside of this object.
To understand this better, you can check the example below:
const mark = 10
const obj = {
name: 'Sardor',
mark: mark,
setMark: function(num) { this.mark = num },
getMark: function() { console.log(this.mark) }
}
obj.getMark() // 10
obj.setMark(8)
obj.getMark() // 8
console.log(mark) // 10
It means, that you filled mark by the date of num. Then you called .setMark() function of obj and changed its value to 8. But you didn't change the variable mark, that is outside of obj. That's why finnaly you have 8 in obj.mark and 10 in mark.
Advice: read more about this
This question already has answers here:
Destructuring and rename property
(2 answers)
Closed 3 years ago.
I've seen this in a repository, but I'm not quite sure what is exactly happening. Is the var value replaced or is the child question of value taken from var data?
const { value: question } = data;
const { value } = data;
Destructuring properties of an object
const { value } = data;
creates a block-scoped constant named value, and assigns to it data.value.
It's identical to
const value = data.value;
Destructuring properties of an object under a different variable name
const { value: question } = data;
creates a block-scoped constant named question, and assigns to it data.value.
It's identical to
const question = data.value;
A property can be unpacked from an object and assigned to a variable with a different name than the object property.
var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true
Here, for example, var {p: foo} = o takes from the object o the property named p and assigns it to a local variable named foo.
MDN - Destructuring assignment
This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 8 years ago.
I am trying to do something like this:
var obj = {
a: 5,
b: this.a + 1
}
(instead of 5 there is a function which I don't want to execute twice that returns a number)
I can rewrite it to assign obj.b later from obj.a, but can I do it right away during declaration?
No. this in JavaScript does not work like you think it does. this in this case refers to the global object.
There are only 3 cases in which the value this gets set:
The Function Case
foo();
Here this will refer to the global object.
The Method Case
test.foo();
In this example this will refer to test.
The Constructor Case
new foo();
A function call that's preceded by the new keyword acts as a constructor. Inside the function this will refer to a newly
created Object.
Everywhere else, this refers to the global object.
There are several ways to accomplish this; this is what I would use:
function Obj() {
this.a = 5;
this.b = this.a + 1;
// return this; // commented out because this happens automatically
}
var o = new Obj();
o.b; // === 6
This should return the correct values:
function () {
var aVar = 5;
var bVar = aVar + 1;
return {
a : aVar,
b : bVar;
}
}();
As it turns out you can't reference an object inside another object unless the first one is a function. But you can do it this way.
var obj = {
a: 5
}
obj.b = obj.a + 1; // create field b in runtime and assign it's value
If you console.log(obj) you will have
obj = {
a: 5,
b: 6
}
This way you keep the object literal structure for the remaining part of the code
No, in your example, the value of this doesn't refer to the object literal.
You'll need to assign a value to b after the object has been created in order to base it on another property in obj.
in chrome debugger
> var o = {a: 5, b: this.a+1}
undefined
> o.b
NaN
> o.a
5
No. this will take the same meaning as it would outside the definition.
This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 8 years ago.
I am trying to do something like this:
var obj = {
a: 5,
b: this.a + 1
}
(instead of 5 there is a function which I don't want to execute twice that returns a number)
I can rewrite it to assign obj.b later from obj.a, but can I do it right away during declaration?
No. this in JavaScript does not work like you think it does. this in this case refers to the global object.
There are only 3 cases in which the value this gets set:
The Function Case
foo();
Here this will refer to the global object.
The Method Case
test.foo();
In this example this will refer to test.
The Constructor Case
new foo();
A function call that's preceded by the new keyword acts as a constructor. Inside the function this will refer to a newly
created Object.
Everywhere else, this refers to the global object.
There are several ways to accomplish this; this is what I would use:
function Obj() {
this.a = 5;
this.b = this.a + 1;
// return this; // commented out because this happens automatically
}
var o = new Obj();
o.b; // === 6
This should return the correct values:
function () {
var aVar = 5;
var bVar = aVar + 1;
return {
a : aVar,
b : bVar;
}
}();
As it turns out you can't reference an object inside another object unless the first one is a function. But you can do it this way.
var obj = {
a: 5
}
obj.b = obj.a + 1; // create field b in runtime and assign it's value
If you console.log(obj) you will have
obj = {
a: 5,
b: 6
}
This way you keep the object literal structure for the remaining part of the code
No, in your example, the value of this doesn't refer to the object literal.
You'll need to assign a value to b after the object has been created in order to base it on another property in obj.
in chrome debugger
> var o = {a: 5, b: this.a+1}
undefined
> o.b
NaN
> o.a
5
No. this will take the same meaning as it would outside the definition.