Reputation: 473
I'm trying to get a copy of an object like this:
graphs = (function () {
var trends = {
pointSize: 10,
};
// Object Oriented JavaScript - pp 109
var lockVariable = function(x) {
return function() {
return x;
}
};
var getTrendsConfig = function() {
return lockVariable(trends)();
};
return {
getTrendsConfig : getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
I was expecting to get printed a "{pointSize: 10}"
Because the getTrendsConfig function would pass the trends object to the lockVariable function, which would return the local value object: "{pointSize : 10}", instead I get "{pointSize: 11}".
I'm taking this from an example of the book "Object Oriented JavaScript" pp 108-109:
How do I get my expected result? Is it possible? And why this doesn't work?
Upvotes: 1
Views: 231
Reputation: 10864
graphs = (function () {
var trends = {
pointSize: 10,
};
// Object Oriented JavaScript - pp 109
var lockVariable = function(x) {
return function() {
return x;
}
};
var getTrendsConfig = function() {
return lockVariable(trends)();
};
return {
getTrendsConfig : getTrendsConfig
};
}());
c = Object.assign({}, graphs.getTrendsConfig()); // same as ...graphs.getTrendsConfig() in ES6 spread syntax
c.pointSize = 11;
console.log(graphs.getTrendsConfig());
console.log("c =", c);
It's not producing your expected result because you re-assigned c.pointSize
to 11
and that's why you're getting 11
;
In JavaScript, assigning an object to a variable is done by reference and not by value. This means that you're simply copying over the object's location in memory, causing any modification to affect the original value.
In your example when you assign c = graphs.getTrendsConfig();
, c
will now point to the same object's location/address.
When you did this c.pointSize = 11
, you modified the same (original) object and not a copy.
Solution:
In other to make a copy of graphs.getTrendsConfig()
you could use Object.assign()
or the new ES6 spread syntax ...
. By making a copy you won't be modifying the original object's pointSize
variable.
Upvotes: 1
Reputation: 943608
Primitive values, such as numbers, in JavaScript, are immutable. You can copy i
to x
(as per the book), change i
and leave x
unchanged.
Objects are not immutable and are only ever addressed by reference. When you return the value of trends
(c = graphs.getTrendsConfig();
), you are returning a reference to the object (so c
and trends
both contain a reference to the same object). When you modify it, you modify that object. Getting another copy of trends
gives you another copy of the reference… which still points to the same object.
The simple way to deal with this is to move the logic that creates the object inside the function that gets called.
graphs = (function() {
var lockVariable = function(x) {
return function() {
return x;
}
};
var getTrendsConfig = function() {
var trends = {
pointSize: 10,
};
return lockVariable(trends)();
};
return {
getTrendsConfig: getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
Although you could simplify that to
graphs = (function() {
var getTrendsConfig = function() {
return {
pointSize: 10,
};
};
return {
getTrendsConfig: getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
To go with something close to what your original code is trying to acheive, you could return an explicit copy of the object by using Object.assign()
graphs = (function() {
var trends = {
pointSize: 10,
};
// Object Oriented JavaScript - pp 109
var lockVariable = function(x) {
return Object.assign({}, x);
};
var getTrendsConfig = function() {
return lockVariable(trends);
};
return {
getTrendsConfig: getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
Upvotes: 1