为啥函数的参数对象不是 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 个方法!:toString
、join
、reverse
和 sort
。 p>
我认为这是他们让 arguments
继承自 Object.prototype
的主要原因之一,当时那些 Array 方法看起来不太有用。
但是Array.prototype
对象在标准的下一个版本中得到了扩展,现在在ES5上,Array对象有map
、reduce
、every
、some
等方法,它们是真的很强大。
去年,在标准的草案阶段,ES5 中有一个提议让 arguments
继承自 Array.prototype
,但后来被放弃了。
在这些草稿中,arguments
继承自 Array.prototype
,但为了向后兼容 ES3,arguments
对象定义了两个自己的属性,toString
和 toLocaleString
,它们都指向 @ 上的相同方法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 函数优先于头部中的函数?
matlab TR = FKINE(ROBOT, Q),Q具体是啥意思,不是已经有个robot对象了吗,为啥还需要参数Q