array re/assignment reference changes - javascript

In javascript arrays are objects therefore passed by reference. So
var a = ["a"];
var b = a;
console.log(b);
a[0] = "wtv";
console.log(b);
will change b value.
what I don't understand is why
var a = ["a"];
var b = a;
console.log(b);
a = ["wtv"];
console.log(b);
is not changing b value ? what is the reasoning behind this ?

Because the value in memory a points to is changed by the assignment a = ["wtv"];.
while in the first example you change a part/property of a, while the object in memory a points to stays the same.
An image to explain it:

It's because you're b is just copying a reference to a.
So they have copies of the same reference, but they each have their own copy of that reference.
var a = ["a"];
// b now holds a copy of the reference from a
var b = a;
// when you change a, b is unaffected since it has an independent reference
// a now points to a new location in memory
// a has a new reference, whereas b still has the reference from before
a = ["wtv"];
However, since the two variable do have the same reference, even though they are copies, you can change data within the object or array itself and have it affect both variables.
Take this for example:
// a points to a location in memory
var a = [];
// we give a some value
a["foo"] = 'bar';
// b now has a *copy* of a's location in memory
var b = a;
// since b shares the same location in memory as a, it has the same foo value
console.log(b.foo); // => bar
// we update a's foo value
a["foo"] = 'baz';
// since b still shares the same location in memory as a,
// it's pointing to the same foo from a, therefore it's also affected
console.log(b.foo); // => baz
#Hidde has a great image that helps visualize what's going on behind the scenes with where the memory is pointing.

With a = ["wtv"]; you assign brand new array to variable a. It has nothing to do with it's former reference.

An array in JavaScript is also an object and objects are always passed/assigned by reference. Thus both variables have a reference to the same object, thus making a change in one will reflect a change in another as both are pointing to the same value.
Whereas in the later case, you are assigning a new value to the var a and this will be stored at different memory location and not on the one on which b is stored, it is similar like doing
var a = 5;
var b = a;
a = a - 1;
alert(b); // alerts 5
alert(a); // alerts 4

Related

why my code works in the second situation but not in the first?

I want to know for what reason the programme is working in the second case but not in the first one.
CASE1:-
let tem=document.getElementById('timed').value
let timeBtn=document.getElementById('timed_input');
timeBtn.addEventListener('click',()=>{
console.log(tem);
})
CASE2:-
let timeBtn=document.getElementById('timed_input');
timeBtn.addEventListener('click',()=>{
console.log(document.getElementById('timed').value);
})
Because value is very likely to be a primitive data type. When you assign a primitive value to a variable, the value is copied to the variable. In contrast, when you assign an object to a variable, you get a reference of the object and not a copy of it.
Take a look at this example.
let a = 20;
let b = a;
a = 30;
console.log(a); // 30
console.log(b); // 20
Even though we assign let b = a, we stored the value of a (20) into b, b and a don't have a relation to each other.
In contrast with non primitive data types, like objects:
let a = { name: "Doria", age: 22 };
let b = a;
b.name = "Nicole";
console.log(a.name); // Nicole
console.log(b.name); // Nicole
In this case, a and b are related, in the sense that they are referencing the same object.

Why is the value of b printed as 23 and not 46?

My code:
var a = 23;
var b = a;
a = 46;
console.log(a);
console.log(b);
Why is the value of b printed as 23 and not as 46?
Output :
a=46, b=23,
In Javascript, Only Objects/Arrays are passed by reference and others are passed by value. As a and b hold integer values they are passed by value.
When var b = a; is executed, b does not "refer" to a. It becomes a number whose value is a's value at this moment.
However, if you use an Object, the attribution will use the reference of a, and not its value:
a = { value: 23 };
b = a;
a.value = 46;
console.log(b);
// console
Object { value: 46 }
Look at this answer. Primitives are passed by values and objects are passed by reference. As a and b are primitives, they are passed by values. And when a is changed that will not be reflected in b.
Because you are giving a value of a, and that is 23. Then you are reassign a to be 46.
in your code first you initialize a with value of 23 and then you assign value of a to b
var a = 23;
var b = a;
a = 46;
console.log(a);
console.log(b);
then you update value of a but not assigning it to b
As in Java-Script Only Objects/Arrays are passed by reference and others are passed by value. As a and b hold integer values they are passed by value.
so updating value of a did not result in change of b value ; if you assign value to b after updating value of a it would result in displaying value of 46 for both a and b
assignment operator means you assign the value of right side to the value of left side so by this statement var b = a; b becomes 23 and once you change a it has no affect on value of b due to lexical scoping of js.

Cannot set backgroundColor when assigned to a variable

Trying to set a background color to the body of the document, I am puzzled as for why the following code does not work (tested in Chrome):
var a = 'blue';
var b = document.getElementById('body').style.backgroundColor;
b = a; // Not working.
while this works fine:
var a = 'blue';
var b = document.getElementById('body').style;
b.backgroundColor = a; // works.
and this works too:
document.getElementById('body').style.backgroundColor = 'blue'; //works
Can someone explain why the first version does not work?
This is a classic pointer user error. I've made this mistake many many times.
var a = 'blue';
var b = document.getElementById('body').style.backgroundColor;
b = a; // Not working.
The above code doesn't work because the value of document.getElementById('body').style.backgroundColor is being copied to the identifier b. When you reassign b with the value of a you're not re-assigning the value of document.getElementById('body').style.backgroundColor.
That why thiis code works:
var a = 'blue';
var b = document.getElementById('body').style;
b.backgroundColor = a; // works.
because you're saving the value of style to the identifier b. b a complex type. Now when you reassign b.style you're also re-assigning document.getElementById('body').style because the identifier b holds the same reference as document.getElementById('body').style.
Let me try to break that down:
In javascript (and many other languages) when you assign a complex type (i.e. an object or an array) to an identifier, you're actually assigning a reference to "something" in memory. You can think of the identifier's value being an "address" instead of holding all the values of the complex type, and when you try to pull values out of the identifier using the obj.prop syntax, you're actually telling the program to go to the address and fetch the desired value.
Therefore, if any property in that "something" changes, the references (aka pointers) will also reflect that change:
const complexType = {
a: 'something'
}
const x = complexType;
const y = complexType;
console.log(`from x: ${x.a}`);
console.log(`from y: ${y.a}`);
complexType.a = 'something else';
// notice how they change
console.log(`from x again: ${x.a}`);
console.log(`from y again: ${y.a}`);
To contrast, simple/primitive types are always copied on assignment. This means that the identifier hold the full value instead of holding an address. That means whenever you assign an identifier to a simple/primitive value, that value will persist even when you change the original value.
// original value
let simpleType = 'something';
let a = simpleType;
let b = simpleType;
console.log(`from a: ${a}`);
console.log(`from b: ${b}`);
// re-assign
simpleType = 'something else';
// notice how they *don't* change
console.log(`from a again: ${a}`);
console.log(`from b again: ${b}`);
So to conclude, document.getElementById('body').style.backgroundColor returns a simple type. This simple type get copied on assignment. That's why you can't do this:
var a = 'blue';
var b = document.getElementById('body').style.backgroundColor;
b = a; // Not working.
Hope that helps!
var b = document.getElementById('body').style.backgroundColor;
Acts like a getter and returns the background color of the element with the ID of body. It doesn't hold a pointer to it the way you seem to be thinking. So b would contain a string like purple or whatever color you set.
Then you're doing b = a; which will just overwrite the value of b with a's value.

Multiple assignment confusion

I understand that the assignment operator is right associative.
So for example x = y = z = 2 is equivalent to (x = (y = (z = 2)))
That being the case, I tried the following:
foo.x = foo = {a:1}
I expected that the object foo would be created with value {a:1} and then the property x will be created on foo which will just be a reference to the foo object.
(This is actually what happens if I was to separate the multiple assignment statement into two separate statements foo = {a:1};foo.x = foo; )
The outcome was actually:
ReferenceError: foo is not defined(…)
So then I tried the following:
var foo = {};
foo.x = foo = {a:1};
Now I don't get the exception anymore but foo.x is undefined!
Why is the assignment not working as I expected?
Disclaimer: The 'duplicate' question seems to be very different to the one that I'm asking, as the issue there is that the variables that were created in the assignment were global, as apposed to variables created with the var keyword. That's not the issue here.
There's an important difference between associativity and order of evaluation.
In JavaScript, even though the assignment operator groups right to left, the operands are evaluated left to right before the actual assignments are performed (which do occur right to left). Consider this example:
var a = {};
var b = {};
var c = a;
c.x = (function() { c = b; return 1; })();
The variable c initially references a, but the right-hand side of the assignment sets c to b. Which property gets assigned, a.x or b.x? The answer is a.x because the left-hand side is evaluated first, when c still references a.
In general, the expression x = y is evaluated as follows:
Evaluate x and remember the result.
Evaluate y and remember the result.
Assign the result from step 2 to the result of step 1 (and return the former as the result of the expression x = y).
What happens with multiple assignments, as in x = (y = z)? Recurse!
Evaluate x and remember the result.
Evaluate y = z and remember the result. To do this:
Evaluate y and remember the result.
Evaluate z and remember the result.
Assign the result from step 2.2 to the result of step 2.1 (and return the former as the result of the expression y = z).
Assign the result from step 2 to the result of step 1 (and return the former as the result of the expression x = (y = z)).
Now let's look at your example, slightly edited:
var foo = {};
var bar = foo; // save a reference to foo
foo.x = (foo = {a:1}); // add parentheses for clarity
foo.x is evaluated before foo gets assigned to {a:1}, so the x property gets added to the original {} object (which you can verify by examining bar).
Edited the answer to make it simple
First of all you have to understand the differnce between Reference- and Value- Type.
var foo = {};
foo variable holds a Reference to an object in memory, lets say A
Now, there are two arts of accessors: Variable Accessor and Property Accessor.
So foo.x = foo = {a:1} can be understood as
[foo_VARIABLE_ACCESSOR][x_PROPERTY_ACCESSOR] = [foo_VARIABLE_ACCESSOR] = {a:1}
!!! Accessor chain is evaluated first to get the last accessor, which is then evaluated associative.
A['x'] = foo = {a:1}
Property Accessor are seperated into setters and getters
var foo = { bar: {} };
foo.bar.x = foo = {a:1}
Here where have decared two nested objects foo and bar. In memory we have then two object A and B.
[foo_VAR_ACCESSOR][bar_PROP_GETTER][x_PROP_ACCESSOR] = [foo_VAR_ACCESSOR] = {a:1}
> A[bar_PROP_GETTER][x_PROP_ACCESSOR] = [foo_VAR_ACCESSOR] = {a:1}
> B[x_PROP_ACCESSOR] = [foo_VAR_ACCESSOR] = {a:1}
> B['x'] = foo = {a: 1}
Here you have little example
var A = {};
var B = {}
Object.defineProperty(A, 'bar', {
get () {
console.log('A.bar::getter')
return B;
}
})
Object.defineProperty(B, 'x', {
set () {
console.log('B.x::getter')
}
});
var foo = A;
foo.bar.x = foo = (console.log('test'), 'hello');
// > A.bar.getter
// > test
// > B.x.setter
Great question. The thing to remember here is that JavaScript uses pointers for everything. It's easy to forget this since it is impossible to access the values representing memory addresses in JavaScript (see this SO question). But realizing this is very important in order to understand many things in JavaScript.
So the statement
var foo = {};
creates an object in memory and assigns a pointer to that object to foo. Now when this statement runs:
foo.x = foo = {a: 1};
the property x is actually getting added to the original object in memory, while foo is getting assigned a pointer to a new object, {a: 1}. For example,
var foo, bar = foo = {};
foo.x = foo = {a: 1};
shows that if foo and bar are pointing to the same object initially, bar (which will still point to that original object) will look like {x: {a: 1}}, while foo is simply {a: 1}.
So why doesn't foo look like {a: 1, x: foo}?
While you are right in that assignments are right associative, you must also realize that the interpreter still reads from left to right. Let's take an in-depth example (with some bits abstracted out):
var foo = {};
Okay, create an object in memory location 47328 (or whatever), assign foo to a pointer that points to 47328.
foo.x = ....
Okay, grab the object that foo currently points to at memory location 47328, add a property x to it, and get ready to assign x to the memory location of whatever's coming next.
foo = ....
Okay, grab the pointer foo and get ready to assign it to the memory location of whatever's coming next.
{a: 1};
Okay, create a new object in memory at location 47452. Now go back up the chain: Assign foo to point to memory location 47452. Assign property x of the object at memory location 47328 to also point to what foo now points to--memory location 47452.
In short, there is no shorthand way to do
var foo = {a: 1};
foo.x = foo;

Javascript multiple assignment clarification?

Looking at var a=b=1; , I already know that both a and b has the same value.
But my question is :
Does the a gets its value from 1 or from b ?
I made a small test :
/*1*/ (function (){
/*2*/ var j = window.j = function (){ alert('3');};
/*3*/ window.j2 = j;
/*4*/ })();
/*5*/
/*6*/ window.j(); //3
/*7*/ window.j=null;
/*8*/ window.j2();//3
As you can see line #8 yields 3 so I persume that a is not having the value of b but the value of 1.
Am I right ?
visualize :
(function (){
var j = window.j = function (){ alert('3');};
|
| ^ ^
| | | //which one ?
+----------+--------+
})();
Assignment in javascript works from right to left. So you are getting your value from window.j. Re-setting window.j will not affect the result because Javascript variables always passes by value, exception is array or object.
Example of passing value by ref in JS object:
var obj = { x: 2 };
var anotherObj = obj;
anotherObj.x++;
alert(obj.x); //3
You can find more information here.
More useful examples available in this answer.
The "=" operator associates to the right so "a=b=1" is equivalent to "a=(b=1)". So 1 is assigned to b first with a result of 1, which is then assigned to a.
Assigment in JavaScript is right associative, so you are correct.
In
a = b = c;
a takes the value of b at time of assignment, so if b is later assigned to something else, a retains its value (which happens to be the same as c)
You are right technically but are confused with reference / value assignment i think. Technically a does get it's value from b but there is no reference to b therefore if your were to do b = null it would have no affect to a, which is what you're seeing in your example.
a inherits the value of b without relying on b still existing or having that same value later on when you refer back to a. The assignment happens right to left so actually reads a = ( b = 1)

Categories