2012-11-22 64 views
7

假设我有这个功能,(对于一些奇怪的原因)其arguments对象返回给调用者:参数对象是否泄漏?

function example(a, b/* ...*/) { 
    var c = // some processing 
    return arguments; 
} 

是否存储(含有a调用(var d=example();)防止example可变环境的结果, b,c等)被垃圾收集? Arguments object的内部设置者和获取者仍然可以引用它,就像从闭包返回的函数一样。

我知道几乎没有用例(并且传递参数对象被认为是不好的练习,很可能是因为它们与数组相似),但这更多的是一个理论问题。不同的EcmaScript实现如何处理这个问题?

+0

关于'arguments'的奇怪之处在于,命名参数实际上是**数组**,用于伪数组的元素。尝试一下!如果你改变'arguments [0]',那么'a'也会改变!我不认为它出于这个原因泄漏。 – Pointy

+1

真的吗?我认为这是另一种方式:'arguments [0]'是'a'的别名:-)规范中描述的算法表明'arguments'的索引是带有“ParameterMap”的setter&getters和链接到调用的环境记录 - 可能泄漏imho的原因。这就是为什么我也在问实际的实现... – Bergi

+0

嗯,我想这是一种神秘的 - 这是一个别名为:-)我在想的是因为参数对象基本**是**它不需要对闭包或任何东西的引用,所以除了它直接使用的内存以外,它不会“钉住”任何其他东西。然而,这只是一种预感,我不知道真实的故事。 – Pointy

回答

3

考虑一下:

var x = function() { 
    return arguments; 
} 
console.log(x() === x()); 

这是假的,因为它是不一样的arguments对象:它的(对于x每个invokation)一个新构造的对象具有值存储中的所有PARAMS的。然而,它的arguments属性:

var y = x([]); 
console.log(y instanceof Object); // true 
console.log(y instanceof Array); // false 
console.log(y.length); // 1 
console.log(y.callee + '');  // function() { return arguments; } 

然而,有更多的这一点。显然,物体送入功能作为其PARAMS不会被GC回收,如果arguments返回:

var z = x({some: 'value'}); 
console.log(z[0]); // {some:'value'} 

这是意料之中的:毕竟,你可以通过声明函数里面的一些本地对象得到类似的结果,分配该函数的第一个参数的值作为其对象'0'属性,然后返回该对象。在这两种情况下,所提到的对象仍然是“正在使用”,所以没有什么大不了的,我想。

但是呢?

var globalArgs; 
var returnArguments = function() { 
    var localArgs = arguments; 
    console.log('Local arguments: '); 
    console.log(localArgs.callee.arguments); 
    if (globalArgs) { // not the first run 
    console.log('Global arguments inside function: '); 
    console.log(globalArgs.callee.arguments); 
    } 
    return arguments; 
} 
globalArgs = returnArguments('foo'); 
console.log('Global arguments outside function #1: '); 
console.log(globalArgs.callee.arguments); 
globalArgs = returnArguments('bar'); 
console.log('Global arguments outside function #2: '); 
console.log(globalArgs.callee.arguments); 

输出:

Local arguments: ["foo"] 
Global arguments outside function #1: null 
Local arguments: ["bar"] 
Global arguments inside function: ["bar"] 
Global arguments outside function #2: null 

正如你看到的,如果回到arguments对象并将其分配给某个变量,函数内部它callee.argument属性指向同一组数据作为arguments本身;这也是预期的。但功能外variable.callee.arguments等于null(不是undefined)。

+0

'variable.callee.arguments'与'arguments'不一样,它是一个非标准的构造。查看我对[这个问题]的回答(http://stackoverflow.com/q/11939736/825789)。 – bfavaretto

0

没有对特定的JavaScript引擎做任何研究,这是很难回答的决定性的。然而,我会认为argumentsObjectexample创建的上下文之间的关系与任何其他局部变量及其主机上下文相同。

也就是说,存储该值不需要存储它的上下文。

一个需要注意的是arguments.callee属性这是一个给定的argumentsObject被绑定到的上下文(即Function)的引用。但是,该属性并不存在于严格模式下,并且也是has been deprecated

除此之外,我认为可以安全地假设返回并存储argumentsObject不会导致内存泄漏。

+0

'argument.callee'只是引用'example'函数,不是吗?我只是询问'example'的执行上下文中的其他值,比如'c'。 – Bergi

+0

是的,就是这样。我不确定你的观点是什么。一个局部变量(如'c')将不会在'arguments'' Object'中被引用。 – FK82

+0

当然,但这是一个问题。读取关于'arguments'对象的规范(http://es5.github.com/#x10.6),参数对象的内部getters/setters会引用变量环境记录(包括'c')。 – Bergi