为啥函数的参数对象不是 Javascript 中的数组?

Posted

技术标签:

【中文标题】为啥函数的参数对象不是 Javascript 中的数组?【英文标题】:Why isn't a function's arguments object an array in Javascript?为什么函数的参数对象不是 Javascript 中的数组? 【发布时间】:2011-03-15 14:58:01 【问题描述】:

由于人们做的第一件事似乎是将arguments 转换为一个真正的数组,我很感兴趣为什么javascript 语言的作者和实现者决定并继续认为arguments 不应该 做一个真正的Array。我并不是说这是诱饵,我真诚地对它背后的想法感兴趣。由于当您在其主体中时自然会调用该函数,所以我不认为这是因为 arguments 引用的对象可以更改,就像某些 DOM 结果一样...

【问题讨论】:

这在 ES6 中不是问题。你可以使用rest parameters,这是一个真正的数组。 【参考方案1】:

我的猜想:

arguments 对象的概念从一开始就存在于语言中,甚至在 ECMAScript First Edition Standard(PDF) 中有描述。

在那个版本的 ECMAScript 中,Array.prototype 非常基本,数组对象只包含 4 个方法!toStringjoinreversesort。 p>

我认为这是他们让 arguments 继承自 Object.prototype 的主要原因之一,当时那些 Array 方法看起来不太有用

但是Array.prototype对象在标准的下一个版本中得到了扩展,现在在ES5上,Array对象有mapreduceeverysome等方法,它们是真的很强大。

去年,在标准的草案阶段,ES5 中有一个提议让 arguments 继承自 Array.prototype,但后来被放弃了。

在这些草稿中,arguments 继承自 Array.prototype,但为了向后兼容 ES3,arguments 对象定义了两个自己的属性,toStringtoLocaleString,它们都指向 @ 上的相同方法987654343@,但最后,委员会决定继续继承Object.prototype

【讨论】:

猜想?看起来你参加了所有的委员会会议……哈哈 谁不知道这件事:slideshare.net/douglascrockford/newandimproved,顺便说一句+1。但它并没有告诉你为什么委员会“继续认为arguments不应该是真正的Array @galambalazs:IMO 委员会决定的原因是,害怕破坏网络,ES5 标准设计得非常仔细,避免了任何根本性的改变,事实上,该语言没有引入新的语法。我谈到的提案,IIRC 被放弃了,因为他们讨论了 extreme edge 不兼容的情况,例如重新定义Object.prototype。我们会看到,也许在未来...... @CMS:改变它的原型会破坏网站并不是猜测,这是一个众所周知的事实。 Opera 以Array.prototype 的身份发布了不到两年。【参考方案2】:

arguments 对象有一个非常不寻常的特性,它的类数组元素是保存函数参数的局部变量的同义词。例如:

function f(x) 
   console.log(arguments[0]);   // Displays the initial value of the argument x
   x = 5;                       // Changes the value of the local variable x
   console.log(arguments[0]);   // Now displays 5

我一直觉得这种“神奇的行为”是arguments 不是数组的原因。

【讨论】:

没错,但我也可以拥有function a() console.log(arguments) ; a(1, 2, 3);... 是的,此行为仅适用于您已命名的参数。 幸运的是,这个 linkage 在 ES5 严格模式下已经被移除了:)(我不喜欢魔法!)。 @CMS:我也不是 :)... 你认为这就是 arguments 没有作为数组实现的原因吗? @Daniel,不,不是不可变的,arguments 对象本身的唯一变化(不管严格模式的各种语义限制),是它的[[Class]] 内部属性包含字符串"Arguments",例如:Object.prototype.toString.call(arguments) == "[object Arguments]";【参考方案3】:

需要注意的是,如果没有一位设计师在场,我们只能猜测为什么。但我们可以想出一些正当的理由......这是我的:

从函数的角度来看,一个原因可能是因为您不能 - 显然 - 实际更改传递给您的参数。您可以更改表示传递给您的参数的数组,但参数在传递时在您收到执行范围之前就已经确定了。

您可以拼接、切块和弹出数组,如果您对arguments 对象执行此操作,那么您就破坏了概念上不可变的结构(可悲的脸!)。实参对象的设计更接近于 JavaScript 可以提供的一种不变性。

类似于查询字符串参数。你会得到一个由发送请求的客户端交给你的集合。它是请求信息的一部分,已经设置完成。

【讨论】:

我不确定我是否完全同意这里的推理。 arguments 只是一个对象,虽然我们无法在技术上更改实际参数,但我们可以对整个 arguments 对象或它通过数组索引表示的单个参数做任何我们想做的事情 - arguments[0]arguments[1]、 ...为什么当时不制作Array,或者给出类似数组的接口仍然值得我说。同样的问题也适用于 NodeList。 @Anurag 我不一定不同意......正如我所说,我们只能推测原因,这是我的理论:) 好点,我认为在 ES5 中创建防篡改对象的选项是一个很好的进步,arguments 可以很好地利用它。对于非常基本的接口,我能想到的一个原因是 ES5 委员会在进行重大更改时基本上对整个 Web 负责,因此不幸的是,它们很慢而且很难实现。【参考方案4】:

arguments 不只是返回参数。它返回被调用对象和参数数组。如果只是一个数组,第一个元素可能是被调用对象,比较混乱。

【讨论】:

也许问题应该是,为什么没有单独的callee 对象?为什么应该是arguments的属性?

以上是关于为啥函数的参数对象不是 Javascript 中的数组?的主要内容,如果未能解决你的问题,请参考以下文章

javascript的Math.round()函数为啥不能精确小数点位数,

为啥正文中的 javascript 函数优先于头部中的函数?

Javascript进阶---函数参数

对JavaScript中的this的理解

matlab TR = FKINE(ROBOT, Q),Q具体是啥意思,不是已经有个robot对象了吗,为啥还需要参数Q

为啥HTML调用JS无效