这很简单。 JavaScript 总是按值传递/分配,但对象的值从不真正分配给变量。在 JS 中考虑对象和内存管理的方式是这样的:
所有对象(无论是函数、对象字面量、数组、原型...)都驻留在内存中的某个位置。内存中的这些空间可以被变量引用,也可以不被引用。但他们保持原样放置。您可以为任意数量的变量分配此对象的地址,但您不能复制对象本身,也不能直接复制。
查看this answer,其中包含许多图表以及有关 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 变量所需的微小内存位。
在此示例中,实际 值是a 或b,类似于0XB16B00B6。或者在 C 语言中,它们实际上表现为一个取消引用的指针。
在某些情况下,人们确实想要复制对象。由于 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 启动时,它将检查所有 标记 位内存并释放它们(释放它们以供使用)。