这很简单。JavaScript 总是按值传递/分配,但对象的值从未真正分配给变量。在 JS 中考虑对象和内存管理的方式是这样的:
所有对象(无论是函数、对象字面量、数组、原型……)都驻留在内存中的某个位置。内存中的这些空间可以被变量引用,也可以不被引用。但他们保持原样。您可以拥有任意数量的变量来分配此对象的地址,但您不能复制对象本身,也不能直接复制。
检查这个答案,其中包含许多图表和有关 JS 如何工作的更多详细信息,包括指向更多信息的链接......
试试看嘛:
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
并b
引用同一个b
对象,不需要额外的内存......保存存储变量所需的微小内存位。在这个例子中,实际值是
什么,或者在这个例子中是什么。或者在 C 语言中,它们实际上表现为取消引用的指针。a
b
0XB16B00B6
在某些情况下,人们确实想要复制对象。由于 JS 的设计,现在这很难实现。如果对象只包含数据,那么最简单的方法是:
var copiedObj = JSON.parse(JSON.stringify(someObject));
但是,如果您正在处理一个也带有自己的方法的对象,那么您将进入一个全新的麻烦世界,您将不得不执行以下操作:
//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;
}
请注意,这段代码只是在我脑海中浮现,并未以任何方式进行测试。它不检查递归,所以使用起来不安全……但我希望你能明白它的要点。
现在,您问题中的代码如何改变内存使用情况?简单:JSON.stringify
返回一个字符串常量。这个字符串不再绑定到原来的对象,所以JS会分配新的内存来容纳这个字符串的内存。然后,这个字符串被传递给JSON.parse
. 同样,将创建一个新对象,需要为此对象(不引用原始对象)分配内存。
分配给 后ajaxdata3
,GC (GarbageCollector) 启动。它会找到对单个对象的 2 个引用,因此该对象不能被 GC'ed。它还将注册第二个对象,该对象被变量引用ajaxdata3
,因此该对象也将保留在内存中。
的返回值JSON.stringify
也找到了,只是这一次,GC 发现这个字符串常量没有在任何地方被引用,所以它标记了内存的那个部分。下次 GC 启动时,它将检查所有标记的内存位并释放它们(释放它们以供使用)。