Javascript 参数对象是否泄漏?

Javascript 参数对象是否泄漏?,javascript,memory-leaks,arguments,closures,Javascript,Memory Leaks,Arguments,Closures,假设我有一个sloppy mode函数,它(出于某种奇怪的原因)将其参数对象返回给调用者: function example(a, b/* ...*/) { var c = // some processing return arguments; } 存储调用结果(var d=example();)是否会防止example(包含a、b、c等)的可变环境被垃圾收集?的内部setter和getter可能仍然引用它,就像从闭包返回的函数一样。演示: 功能示例(a、b){ var c

假设我有一个sloppy mode函数,它(出于某种奇怪的原因)将其
参数
对象返回给调用者:

function example(a, b/* ...*/) {
    var c = // some processing
    return arguments;
}
存储调用结果(
var d=example();
)是否会防止
example
(包含
a
b
c
等)的可变环境被垃圾收集?的内部setter和getter可能仍然引用它,就像从闭包返回的函数一样。演示:

功能示例(a、b){
var c=Array(1000).fill(0);//某个大对象
返回{
args:参数,
集合:函数(x){a=x;},
get:function(){returna;}
};
}
var d=示例('init');
log(d.get());
d、 args[0]=“参数更新”;//指定'a'变量
log(d.get());
d、 set(‘变量更新’);
console.log(d.args);//读取'a'变量
考虑以下事项:

var x = function() {
  return arguments;
}
console.log( x() === x() );
这是错误的,因为它不是相同的
参数
对象:它(对于
x
的每次调用)是一个新构造的对象,其中存储了所有参数的值。但它具有
参数的属性

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; }

然而,这还有更多。显然,如果返回
参数
,则GC不会收集作为其参数发送到函数中的对象:

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
对象并将其分配给某个变量,则在函数内部,其
被调用方。argument
属性指向与
arguments
自身相同的数据集;这也是意料之中的。但是在函数之外,
variable.callee.arguments
等于null(未定义)。

如果没有对特定的JavaScript引擎进行任何研究,则很难得出结论。然而,我认为
参数
对象
示例
创建的上下文之间的关系与任何其他局部变量及其宿主上下文的关系相同

也就是说,存储值并不需要存储其上下文

一个警告是
参数.callee
属性,它是对给定
参数
对象绑定到的上下文(即
函数
)的引用。但是,此属性在严格模式下不存在,并且也不存在


除此之外,我认为可以安全地假设返回和存储
参数
对象
不会导致内存泄漏。

关于
参数
的奇怪之处在于,命名参数实际上是伪数组元素的别名。试试看!如果更改
参数[0]
,则
a
也将更改!我不认为它是因为这个原因泄漏的,真的吗?我认为情况正好相反:
arguments[0]
a
的别名:-)规范中描述的算法表明
arguments
的索引是带有“ParameterMap”和调用环境记录链接的setter和getter,这可能是泄漏imho的原因。这就是为什么我还要问实际实现的原因……我猜这是一个谜,它是一个别名:-)我想的是,因为arguments对象基本上是一组参数,它不需要引用闭包或任何东西,所以除了它直接使用的内存之外,它不会“锁定”任何其他东西。然而,这只是一种预感,我不知道真实情况。FWIW,strict模式切断了形式参数和arguments对象之间的连接。改变一个不会改变另一个。换句话说,每一个都有它自己的传递参数的副本。哦,元效应…这会在7年后重新打开吗?
参数。被调用方
只是引用了
示例
函数,不是吗?我只询问了
example
执行上下文中的其他值,比如
c
。是的,它就是这样做的。不过,我不太确定你的观点是什么。局部变量(如
c
)将不会在
参数中引用。读取参数时,对象的内部getter/setter确实引用了变量环境记录(包括
c
)。我引用:“arguments对象是通过调用抽象操作CreateArgumentsObject创建的,其中(…)env是函数代码(…)的变量环境。”非常确定env指的是封闭上下文而不是封闭上下文。
variable.callee.arguments
arguments
不同,这是一个非标准的构造。看看我对你的回答。