简短的回答:是的。未在任何地方引用的对象将完全从内存中删除,无论该对象属性引用了什么。
在您的代码段中,事情相当简单,但当您开始使用闭包时,内存管理可能会变得棘手:
var objA = (function()
{
var objAb = {who:'An object literal in closure scope',globalReference:'None!'};
return {who:'Return value, is an object literal that references a closure object'.
closureObj : objAb};
})();
var objB = {who:'some object',objAb:{who:'object literal, referenced by objB.objAb'}};
var objBAb = objB.objAb;//reference to obj literal, referenced by objB.objAb
var objAb = objA.closureObj;//reference to obj literal, referenced by objA.closureObj, which in turn references the closure object literal
delete objB.objAb;
console.log(objBAb);//<-- the object literal that was declared as a property of objB still exists
delete objAb;//<-- this reference is gone, but the closure obj still exists
console.log(objA.closureObj);//<-- object is there
基本上,对象是无名的实体。用于访问它们的变量是引用,永远不会包含实际对象本身。它漂浮在 JS 空间中。当您使用 时delete someVar
,您所做的就是取消设置该变量的实际值,这是一个内存地址(有点)。
如果 JS GC 找不到任何引用内存中包含对象的位置的变量,它将回收该内存。
就这么简单。
当您将此逻辑应用于以下代码时:
var objA = (function()
{
var closureObj = {iam:'An object literal defined inside a closure scope'};
var functionsAreObjects = function()
{//nameless function object, inside closure scope, too
return closureObj;
};
var resetFunction = function()
{
this.closureReference = functionsAreObjects();//assign return value to this
};
return {iam:'The returned object literal',
closureReference:closureObj,
reset:resetFunction,
getClosureReference:functionsAreObjects};
})();
delete objA.closureReference;//the closure object IS NOT GC'ed
在前面的示例中,最后一个 delete 语句足以 GC 闭包对象字面量。但是,现在objA
有两种方法(引用函数对象的属性)。这些方法仍然引用闭包对象,并且仍然被 引用objA
,所以closureObj
还不能被 GC'ed。所以,这就是事情变得棘手的地方:
delete objA.closureReference;
delete objA.reset;
delete objA.getClosureReference;
我们已经删除了所有可以链接回closureObj
. ——呃,不完全是。Chrome 的 V8 确实会释放内存,但我听说过类似的代码会导致 Opera 中的泄漏,而且 IE 可能不会擅长回收内存。
此外,我们已经有效地创建了一个getter方法getClosureReference
,所以在现实生活中,这很可能会发生:
//do stuff
delete objA.closureReference;
var objB = objA.getClosureReference();//<-- created new reference to closure object
//do some more stuff
delete objA.reset;
delete objA.getClosureReference;
在这种情况下,closureObj
不能 GC'ed,因为它仍然被objB
某处引用。只有当该变量超出范围时才会closureObj
被释放。这不仅是一个反对全局变量的非常可靠的论据(它们永远不会超出范围,因此永远不会被 GC),它还表明闭包,尽管它们很整洁,但需要开发人员更多的开销:变量超出范围并不一定意味着内存被释放:某些闭包可能会公开对对象的引用,或者引用该对象的函数......
不久前我就这个问题发布了一个问题,但它可能解释了一些事情。
只是为了好玩,如果您想要一个嵌套闭包的示例(闭包中的闭包、闭包中的闭包、相互传递引用以及其他对象),请尝试在以下代码中找出什么时候可以进行 GC