Javascript参数转移

时间:2015-05-26 12:49:23

标签: javascript arguments

我们假设我们有以下功能:

var a = function(data, type){
  var shift = [].shift;
  shift.call(arguments);
  shift.call(arguments);
  shift.call(arguments);
  shift.call(arguments);
  console.log(data);
}

a(1,'test', 2, 3);

我理解数据和类型只是对参数中特定值的引用。但为什么最终数据等于3?

5 个答案:

答案 0 :(得分:3)

来自https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode#Making_eval_and_arguments_simpler

  

严格模式使arguments不那么神奇。

     

在第一个参数为arg的函数中的普通代码中,   设置arg也设置arguments[0],反之亦然(除非否   提供了参数或 arguments[0]已删除)。

     严格模式函数的

arguments个对象存储原始对象   调用函数时的参数。 arguments[i]无法跟踪   相应的命名参数的值,也不是命名的   参数跟踪相应arguments[i]中的值。

你实际上遇到了"除非删除了参数[i]" case;)

答案 1 :(得分:2)

你得到的是一个带有[data,type]的参数数组,还有两个没有被使用的参数。在每个班次之前和之后添加一个console.log,你会看到会发生什么;

var shift = [].shift;
console.log("args", arguments)
console.log(data, type);
// Outputs [1, 'test', 2, 3] => data = 1, type = 'test'

shift.call(arguments);
console.log("args", arguments)
console.log(data, type);
// Outputs ['test', 2, 3] => data = 'test', type = 2

shift.call(arguments);
console.log("args", arguments)
console.log(data, type);
// Outputs [2, 3] => data = 2, type = 3

shift.call(arguments);
console.log("args", arguments)
console.log(data, type);
// Outputs [3] => data = 3, type = 3 (type is keeping it's old value)

shift.call(arguments);
console.log("args", arguments)
console.log(data, type);
// Outputs [] => data = 3, type = 3 (both are keeping their old value)

这有帮助吗?

答案 2 :(得分:0)

以下是代码的逐步介绍。

var a = function(data, type){
  var shift = [].shift;//data points to arguments[0], or 1
  shift.call(arguments); // arguments[0] is now 'test'
  shift.call(arguments); // arguments[0] is now 2
  shift.call(arguments); //arguments[0] is now 3
  shift.call(arguments); // data pointed @ 3, arguments[0] is undefined
  console.log(data);
}

a(1,'test', 2, 3);

JS似乎在后台做了一些工作,如果相应的arguments索引(不是一个数组)从truthy变为falsy / undefined,则保留前一个值。 / p>

答案 3 :(得分:0)

您所观察到的仅适用于非严格的JavaScript,因此不应该依赖它。请参阅http://www.ecma-international.org/ecma-262/5.1/#sec-10.6,其中有一节介绍了严格和非严格模式之间的不同行为。

Sp00m发布了nice explanation from MDN

来自EcmaScript规范

  

注1:对于非严格模式函数,数组索引(在15.4中定义)命名数据属性的参数对象,其数字名称值小于相应函数对象的形式参数的数量,最初与其共享它们的值。函数执行上下文中对应的参数绑定。 这意味着更改属性会更改参数绑定的相应值,反之亦然。如果删除并重新定义此属性或将属性更改为存取属性,则此对应关系将被破坏。对于严格模式函数,arguments对象的属性值只是传递给函数的参数的副本,并且属性值和形式参数值之间没有动态链接。

var a = function(data, type){
  var shift = [].shift;
  shift.call(arguments);
  shift.call(arguments);
  shift.call(arguments);
  shift.call(arguments);
  console.log(data);
}

var b = function(data, type){
  'use strict';
  var shift = [].shift;
  shift.call(arguments);
  shift.call(arguments);
  shift.call(arguments);
  shift.call(arguments);
  console.log(data);
}

a(1,'test', 2, 3); // 3
b(1,'test', 2, 3); // 1

答案 4 :(得分:0)

在您的情况下,'data'是对arguments数组的第一个位置的引用。 当您调用函数时,值为

arguments[0] => data => 1
arguments[1] => type => 'test'
arguments[2] => 2
arguments[3] => 3

docs表示数组函数移位它会删除第一个元素。但也说

  转移是故意通用的;可以调用此方法或将其应用于类似于数组的对象。不包含反映一系列连续的,从零开始的数字属性中的最后一个的长度属性的对象可能无法以任何有意义的方式运行。

在内部,shift函数调用delete运算符。应用四次后,arguments数组为[undefined,undefined]。现在问题是在变量上调用delete会删除它,但是如果仍然存在对变量的引用,则不会删除该值

delete arguments[0];
delete arguments[1];
console.log(arguments); => [2: 2, 3: 3] // Position 0 and 1 were removed. Lenght is still 4
console.log(data);  => 1
console.log(type);  => 'test'

因此,无论您是从参数中删除了值,都会看到变量仍然被引用。