I stumbled upon a very weird behavior inside a javascript closure. If a “global” variable of a closure is a object, any assignment made from it to another variable behaves like some kind of pointer. A simple code should explain better what I mean:
function closure() {
var foo = {key1 : 'value 1'};
return {
method: function(){
var bar = foo;
bar.key2 = 'value2';
return 'foo has attributes : ' + foo.key1 + ' and ' + foo.key2
}
}
}
var someVar = closure();
someVar.method(); // returns "foo has attributes : value 1 and value2" (!!!)
I would obviously expect to obtain foo has attributes : value 1 and undefined as only bar has been modified… However, the script actually modifies both bar and foo with confuses me a lot.
I noticed as well that when foo and bar are strings or numbers everything works as expected – modifying bar does not affect foo.
function closure() {
var foo = 10;
return {
method: function(){
var bar = foo;
bar += 1;
return 'foo is : ' + foo + ' and bar is ' + bar
}
}
}
var someVar = closure();
someVar.method(); // returns "foo is : 10 and bar is 11"
I spent whole evening trying to figure out the reason of this behavior… no luck. I got the same results is SpiderMonkey and V8 (both on Chrome and node.js).
What I want to do is of course to modify bar from the first example without affecting foo. Any help will be very appreciated.
When you do
var bar = foo;, bothbarandfooare pointing to the same object. If you don’t wantfooto change, you need to clonefoo. When you clone, you will get an entirely new object, andbarwill point to that. This answer has some information regarding the cloning of objects in Javascript.Also, this behavior isn’t limited to a closure. It will happen in regular Javascript code:
Will show
fooas having the propertiesa,b, andc.What you’re seeing is standard behavior of most object-oriented languages. When you are dealing with objects, you are dealing with references to those objects instead of the specific instance-values. You don’t see this with numbers because in Javascript they are primitive types, so you’re dealing with the actual values rather than a reference to those values.