It's quite simple. JavaScript always passes/assigns by value, but an object's value is never really assigned to a variable. The way to think about objects and the memory management in JS is something like this:
All Objects (be it functions, object literals, arrays, prototypes...) reside somewhere in memory. These spaces in memory can either be referenced by a variable or not. But they stay put as it were. You can have any number of variables that are assigned the address of this object, but you can't copy the object itself, not directly anyway.
Check this answer which contains a number of diagrams and some more details on how JS works, including links to even more info...
Just try:
var a = {foo: 'bar'},
b;
b = a;
console.log(b.foo);//bar
b.foo += ' appended through b reference';
console.log(a.foo);//bar appended through b reference
a
and b
reference the same object, no additional memory required... save for the minute bit of mem required to store the b
variable.
What the actual value is of a
or b
in this example is something like 0XB16B00B6
. Or in C-speak, they actually behave as a dereferenced pointer.
In some cases, people do want to copy objects. Now this is quite hard to accomplish, owing to JS's design. If the object contains nothing but data, then the easiest way of doing this is:
var copiedObj = JSON.parse(JSON.stringify(someObject));
But if you're dealing with an object that also carries its own methods, then you're in a whole new world of trouble, and you'll have to do something like this:
//after doing:var copiedObj = JSON.parse(JSON.stringify(someObject));
function copyFunctions(srcObj, targetObj)
{
var prop;
for (prop in srcObj)
{
if (srcObj[prop] instanceof Object)
{
if (srcObj[prop] instanceof Function)
{
targetObj[prop] = srcObj[prop];//this is a REFERENCE, still
//OR, to ensure correct this binding!
targetObj[prop] = (function(rebind, actualFunc)
{
return function()
{
actualFunc.bind(this);
var returnVal = actualFunc.apply(this, [].slice.call(arguments));
actualFunc.bind(rebind);
};
}(srcObj, srcObj[prop]));
}
else
{
if (srcObj.hasOwnProperty(prop))
{//avoid copying prototypal methods
targetObj[prop] = copyFunctions(srcObj[prop], targetObj[prop] || {});
}
}
}
}
return targetObj;
}
Please note that this code is just off the top of my head, and is not tested in any way. It doesn't check for recursion, so it's not safe to use... but you get the gist of it, I hope.
Now, how could the code in your question alter the memory usage? Simple: JSON.stringify
returns a string constant. This string has no binding to the original object any longer, so JS will allocate new memory to accomodate the memory for this string. Then, this string is being passed to JSON.parse
. Again, a new object will be created, allocating memory for this object (that does not reference the original object) is required.
After assigning to ajaxdata3
, the GC (GarbageCollector) kicks in. It'll find 2 references to a single object, so that object can't be GC'ed. It'll also register a second object, which is being referenced by the variable ajaxdata3
, so that object, too, will remain in memory.
The return value of JSON.stringify
is found, too, only this time, the GC sees that this string constant isn't being referenced anywhere, and so it flags that section of the memory. The next time the GC starts up, it'll check all flagged bits of memory and deallocate them (free them for usage).