Copied object generated by Object.Assign() function has side effect? - javascript

I have an object named result which is composed of two objects like :
const a = {bar: {baz: 2}};
var b = {foo: 1};
var result = Object.assign({}, a, b);
console.log(result, a, b);
// result -> {bar: {baz: 2}, foo: 1}
// a -> {bar: {baz: 2}}
// b -> {foo: 1}
Now, I am changing the bar property of the result object like:
result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);
// result -> {bar: {baz: 3}, foo: 4}
// a -> {bar: {baz: 3}} intresting part
// b -> {foo: 1} intresting, too!
(You can copy and paste code to javascript console in order to see the result for both cases by the way)
There are two weird things here. First one is that I am changing the resulting object's property, but constant object a's property changes, too. Even if first one is the case with Object.assign function, how can I change the constant variable? Let's say this is the case despite const variable mutation, then why the change in property foo does not reflect to the object b?
I came with that because I generally use Object.assign to copy objects, but this is pretty weird issue with that function I guess. Any ideas about the case? Thank you.

Declaring a variable with const only prevents it from being changed to another value. It doesn't prevent the data referenced by that value to change.
const foo = {prop: 'bar'};
foo.prop = 'baz'; // Works well
foo = 'baz'; // TypeError: invalid assignment to const `foo'
If you want to prevent an object from being changed, you can freeze it.
Object.freeze(foo);
foo.prop = 'buz'; // TypeError: "prop" is read-only
However, that will only affect own properties. If the value of one of these is another object, it won't become frozen.
This is what happens with Object.assign too. It only copies own properties, and if their value is an object, it won't "clone" it. That is, the references will still be the same, and changes will be reflected.
If you want to deeply clone an object, see What is the most efficient way to clone an object?

Object.assign will work but with the added gotcha that if any of the properties you are assigning from contain an object as a value it does not create a copy of that object, so the references do not change, the property in the created object will point to that same nested object.
Also constant in javascript can be deceiving, you can add and remove properties from a 'const' object as long as you don't try to reassign it to a new object or a different primitive.
Same will occur with arrays, you can create a 'const' array but push pop off of it.
https://jsfiddle.net/eu9yg37s/6/ just something I was messing around in to attempt to display what I mean.
const a = {bar: {baz: 2}};
var b = {foo: 1};
// Example of customizer function that may take into account nested objects and properly copy them using lodash 4.x
var customizer = function(objValue, srcValue) {
if (typeof srcValue === 'object' && typeof srcValue !== null) {
return _.assignWith({}, srcValue, customizer);
}
return _.isUndefined(objValue) ? srcValue : objValue;
}
// This calls assign, but will invoke the customizer function
var result = _.assignWith({}, a, b, customizer);
result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);
// 'Constant' Array Example
const hi = [true, false, 'hi'];
hi[2] = 23;
console.log('hi.pop', hi.pop());
console.log('hi', hi);
// These will error, uncomment out to see it errors on any of these attempts
//hi = 3;
//hi = 'no';
hi = [true, false, 23];
//hi = false;
//hi = {};
The change doesn't reflect in b, because it wasn't a nested object during the assign operation so the property foo in our created object is pointing to a new primitive 1

Related

How to update global object value?

I am not sure about best practice that how to deal with it:
const obj = {a: null}
function getObject(){
// I may return a, or anything that could be nested property
return obj.a
}
let v = getObject()
v = 'updated'
console.log(obj.a) // null
I expect a value co-operates with v assignment. I have seen with operator but people say avoid using it. So, what should I be using?
If a function returns the value of a field/variable then you get a reference to the object stored in that field/variable, not a reference to the variable itself. You either need to have getObject() return an object, which you then set the field value on, like so:
function getObject(){
return obj;
}
getObject().a = 'something';
Or you need to write a function that assigns the field value instead, like so:
function setValue(val) {
obj.a = val;
}
Another option would be to wrap your values in objects, so getObject never returns null, instead returning an empty object on which you set a field value, like so:
const obj = {a: {}}
function getObject(){
return obj.a
}
let v = getObject();
v.value = "foo";
// obj now equals {a: {value: "foo"}}
As written you're returning the value currently stored in a, saving that to a variable, then changing the value in the new variable. The value in obj remains unchanged.
You can access any Javascript object using dot like what you had in getObject , also you can set value to the object like this anyObject.key = value this will change the value of the key in the object.
const obj = new Object({ a : null })
Object.prototype.setA = function(a) {
this.a = a
}
obj.setA('hello world!')
console.log(obj)
If you want to update a global object values you need to access the object and assign it
const obj = {a: null}
function getObject(){
return obj.a
}
let v = getObject()
console.log(getObject()) //null
console.log(obj.a) // null
obj.a = "a" //you are now overriding what was null here
console.log(obj.a) //contains "a" now or whatever type you want it to be
I'd recommend you check this helpful tutorial: https://www.w3schools.com/js/js_objects.asp
Understanding JS variables is important:
let a = 1;
console.log(a); //1
a = 2;//overrides a
console.log(a); //2
What you are trying to achieve is not very clear but I would recommend to always mutate the global var to avoid errors and confusion.
Short answer:
you are changing the value of v and not changing the object referenced by v
Long answer:
If this was written in a class-based langauge (like C, java, or C++, etc.), this would also not change a. Because you are only changing what v points or reference to (in case of pointers).
In C :
void *v = (void*) &getObject() // v is equal to obj (or points to obj) obj
v = (void*) &some.thing.something() // v is now equal to some.thing.something() or points to some.thing.something()
// obj has not changed
print(obj.a) // null which is reasonable
// printf ("%s", obj.a); is the correct syntax in C
To actually change a you need to change the value of of the address in memory that is referenced by v
In C:
void *v = (void*) &getObject()
*v = (void *) some.thing.something()
print(obj.a) // now obj is equal to 'some.thing.something()'
// printf ("%s", obj.a); is the correct syntax in C
Now in your code why a is not changing ?
When it comes to Javascript, it is a langauge based on prototypes, rather than class-based
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
Check the link above.
It is because of the same reason explained in the first C code above. You are just changing the value of v and not changing the object referenced by v
let v = getObject()
v = 'some.thing.something()'
console.log(obj.a) // null

Arrays contain value call by Reference so their pointer should turn same values and equate to true

As far as I know, the arrays and objects always act as pointers and just point to somewhere a memory location.
In the following example, as var a is updated, so as b pointing to same memory location as a, should also be updated and final answer should be true, true.
Why is it not happening??? At what instance of time, b gets a different pointer than a and why???
Example:
var a = [2,3,5];
var b = a;
a = [33,45];
console.log(a,b);
console.log(a==b,a===b);
However, to support my clause kindly look at following unchanged values example. Here I am sure both a and b point to same memory location containing data as [2,3,5]. They got same values and are always equated as true.
var a = [2,3,5];
var b = a;
console.log(a==b,a===b);
Because you are not updating the reference of the new object [33, 45].
Following code might help you understand better.
a = [{'a': 1}, {'b': 2}];
b = a;
console.log(a, b);
// creates new object and assigns to the same variable
b = b.concat ([{'c': 3}]);
console.log(a, b);
// but property of object is still referenced in by a and b
b[0].a = 100;
console.log(a,b);
a[2].c = 100; // throws exception, because 'a' does not have the reference to object which refers the object created in 'b'
console.log(a,b);
look at blow:
var a = [2,3,5];
var b = a;
and after the a = [33,45];
the pointer is point to a new obj, not the obj changed

How to make each key of an object as a variable with the same name as the key in Javascript?

I have a javascript object like this:
var obj1={a:1,b:2,c:3}
From this i need to extract each key as a variable like this:
var a=1
var b=2
var c=3
How can this be done?
It can be done using ES6 destructuring, you can explode all the object's properties and assign it in a variable the same as the property's name
var {a,b,c} = obj1;
console.log(a);
console.log(b);
console.log(c);
It's not a great looking solution (this isn't the sort of thing you should be doing - better to work with just the initial object), but you could assign all properties of obj1 to the window object, allowing you to reference them standalone, without having to know the keys beforehand:
var obj1 = {
a: 1,
b: 2,
c: 3
};
Object.assign(window, obj1);
console.log(c);
Try with:
var obj1={a:1,b:2,c:3}
let keys = Object.keys(obj1)
keys.forEach(key => {
let value = obj1[key.toString()];
console.log(key); // Use Key
console.log(value) // Use Value
})

javascript function this and prototype

The code is below:
function A() {
this.name = "kl";
this.obj2 = { a: 1 };
}
A.prototype.city = "china";
A.prototype.obj = {age: 30};
var a = new A();
var b = new A();
a.name = "kobe";
a.obj.age = 20;
a.city = "American"
a.obj2.a = 30;
console.log(b.name); // k1
console.log(b.city); // why china ?
console.log(b.obj); // when b.city = china, why b.obj = {age: 20}
console.log(b.obj2); // {a: 1}
My opinion is that a and b has its own this, so how you edit this[property] you can't change b its own this.value;
property declare so share property ? is right ?
but when obj is change will effect b.obj,
when city change will not effect b.city ?
Both objects have city and obj in their prototype chain. However, if you do a.city = "American" you are creating a new property city on a itself, shadowing the property city in the property chain.
Assigning to a property will (almost) always create that property on the object itself.
a.obj.age = 20; however reads (not assigns!) the object referenced by a.obj and updates its age property. a and b have the same prototype and thus a.obj and b.obj resolves to the same object. If the object is mutated in any way it will affect a and b in the same way.
Structure from the Chrome console:
Let's go through this line by line:
First of all, A.prototype points to an object.
When you run var a = new A();
You create a new object which is set to 'this'
This new object has properties name and obj2 which have values kl and { a: 1 }
this object is linked to the object A.prototype points to, thus a prototype chain is set up.
at the end of function A, the function actually runs return this;, which literally returns the object created to be assigned to a.
var b = new A(); does the same as above
when you run a.name = "kobe";, you're modifying the value from kl to kobe
when you run a.city = "American";, you're creating a new property city on a itself
and when you run a.obj2.a = 30;, you're also only modifying a value.
But when you run a.obj.age = 20;, something is different
a doesn't have the property obj on itself, so it goes up the prototype chain to the object A.prototype points to, and finds the property obj, so this line of code is actually modifying that obj, and changes the value of obj.age from 30 to 20.
when you execute b.name, since b has property name with value kl, so it prints kl
However, b doesn't have the property city on itself, so it goes up the prototype chain to the object A.prototype points to and see if it can find one, which it does, as previously you ran A.prototype.city = "china";, so it prints china.
When console.log(b.obj); is run, b goes up to the prototype chain and find obj on the object A.prototype points to, so it prints {age: 20}

Need Comparison of Object of same type to know the difference in javascript

I need to compare the object to know what properties are changed and what properties are added new.
Is there any code snippet which will loop through entire object and its properties and alert if any changes exist and continue its process till the end.
Consider i need to compare the gridpanel(object) in extjs before and after show and hide event of its parent panel.
Thanks in advance
If you simply want to check if two objects of the same class differ:
function differ(a, b) {
for (var i in a) {
if (a.hasOwnProperty(i) && b.hasOwnProperty(i) && a[i] === b[i]) {
return true;
}
}
return false;
}
a = {foo: 1, bar: 2};
b = {bar: 2};
alert( differ(a, b) ? "Objects differ" : "Objects are the same" );
If that's not what you're after, explain your problem in more detail.
I had a similar problem when I was adding objects to an array. I wanted to be sure, that the same object is not added twice.
I found a helper function for ExtJS which implements a function that compares objects based on the values contained by the object:
https://github.com/nmishra/helpers.js
It then can be used like this:
var obj1 = {foo: 'bar'},
obj2 = {foo: 'bar'},
equality = Ext.ux.util.Object.compareObject(obj1, obj2);
console.log(equality);

Categories

Resources