4

Working on a NodeJS project, I came a across this very unexpected behaviour that I can't figure a way around - it seems like a bug to me, but perhaps I'm simply misunderstanding how NodeJS modules operate.

I've reduced it into a testcase as follows:

mod.js module

exports.process = function(obj) { obj.two = 'two'; };

test.js file

var testObj = {one: 'one'};


console.log(['Before:', testObj]);

var cachedObj = testObj;
require('./mod').process(cachedObj);

console.log(['After:', testObj]);

Then running $ node test.js gives me this:

[ 'Before:', { one: 'one' } ]
[ 'After:', { one: 'one', two: 'two' } ]

I'm assigning the value of testObj to cachedObj, and testObj is never being passed to the module method. testObj should (as far as I can see) never be modified at all.

In fact, cachedObj should surely never be modified either, as it is never returned from the mod.process method. Where am I going wrong?

(running Node 0.6.9)

lucideer
  • 3,842
  • 25
  • 31

3 Answers3

6

It's not a bug, it's perfectly expected behavior.

Variables in JavaScript are passed by reference, so the original object is mutated by the assignment in process.

AKX
  • 152,115
  • 15
  • 115
  • 172
  • This is something of a revelation.. how have I missed this after years working with JS. For future reference - any advice for object cloning patterns? I assume Object.create() will work in Node, but I guess IE7 might be a different issue... – lucideer Feb 24 '12 at 10:35
  • I can think of a couple approaches: jQuery has deep copy mode in its `$.extend` function; `JSON.parse(JSON.stringify(obj))`; ... oh, and heh, Stack Overflow search. :) http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object – AKX Feb 24 '12 at 11:03
  • I did find that Q while searching, but the options are `eval`, `JSON` (IE8+) or jQuery (non-native). I suppose recursion is the next best fallback option then? Who knows I may never need it, I seemingly haven't sofar... – lucideer Feb 24 '12 at 11:09
  • 1
    The source for $.extend is here, if you want to take a look for any purpose. https://github.com/jquery/jquery/blob/master/src/core.js#L303 – AKX Feb 24 '12 at 11:25
  • Wow. That's significantly simpler than I expected it to be. Thanks again. – lucideer Feb 24 '12 at 12:08
3

Objects are passed by reference.

var testObj = {one: 'one'}; // <--- Object
var cachedObj = testObj; // cachedObj and testObj point to the same object,

Since cachedObj and testObj point to the same object (cachedObj === testObj is true), modifying a property of cachedObj will also result in a modified testObj.

Rob W
  • 341,306
  • 83
  • 791
  • 678
1

cachedObj and testObj refers to the same object literal, so if you modify one variable, it is of course seen in both since the variables are just aliases referring to the same object.

Also, objects are passed by reference in JavaScript, so if you modify it inside process.js, the object will be modified.

PatrikAkerstrand
  • 45,315
  • 11
  • 79
  • 94