为什么JavaScript里函数的arguments只是array-like object?

只是标准这么规定的,还是有什么设计原因在里面?

JavaScript的函数里面的arguments对象有 .lengh 属性和可以通过 [] 访问,但是确实从Object.prototype继承的。很多时候都会用 Array.prototype.slice.call(arguments) 或者 Array.from(arguments) 转成数组。直接设计成数组不是更好吗?

 
 

这个问题又激起了我的八卦之心!

在一番寻找之后,找到了似乎是目前网上仅存的 Brendan Eich 本人探讨 arguments 的资料,是一份录音:https://web.archive.org/web/20110822021124/http://minutewith.s3.amazonaws.com/amwb-20101115.mp3 (来自 aminutewithbrendan.com 这个已经被关闭的网站,似乎是和当时的赞助事件调查有关所以被关掉了,但是 archive.org 有存档哈哈)

大致上,BE 本人也承认 arguments 的设计是因为当时只花了十天所以整得太糙了。在正式规范化 JavaScript 的时候,Microsoft 曾经有人提出把 arguments 改成真正的 Array,BE 本人甚至都打算动手改实现了,但是 MS 那边回去商量了下又回来觉得多一事不如少一事,不改了。于是这个糟糕的设计就从此成为了规范... 这是 1997 年的第一版 ES 规范。

除了 arguments.callee 之外,还有一个神奇的 quirk,那就是 arguments 和实际的参数变量之间的迷之绑定。规范里是这么说的:

In the case when iarg is less than the number of formal parameters
for the function object, this property shares its value with the corresponding property of the activation object.
This means that changing this property changes the corresponding property of the activation object and vice
versa. The value sharing mechanism depends on the implementation.

换言之,假设一个函数的第一个参数是 a,当你修改 a 的值的时候,arguments[0] 也会同步变化:

(function (a) {
console.log(arguments[0] === a) // -> true
console.log(a) // -> 1 // 修改 arguments
arguments[0] = 10
console.log(a) // -> 10 // 修改参数变量
a = 20
console.log(arguments[0]) // -> 20
})(1,2)

后面的事情你也知道了,ES 规范是要向后兼容的,而且上面的这个 quirk 使得它在引擎实现中需要很多特殊处理,一旦改动,兼容性影响巨大,所以它永远也改不了了。据说在 ES5 讨论时也有人提出要把 arguments 改成 Array 的 subclass,但是很快就不了了之,只是在 strict mode 下对 arguments.callee 和上面的绑定 quirk 进行了限制。直到 ES6 终于对 arguments 提供了一个替代品 - rest parameters:

function foo (...args) {
// 这里 args 终于是真正的 Array 了!
}

BE 本人并没有提到为什么一开始会把 arguments 设计成对象,因此我们也只能做猜测。但一个合理的推测是,ES1 里面的 Array.prototype 其实很弱,只有四个方法:toString, join, reverse 和 sort - 连 push, pop, shift, unshift, splice 都没有!而 forEach, filter, map, reduce 这些有用的方法更是 ES5 才添加进来的。所以当时 arguments 就算真的继承自 Array 貌似也没什么大用,所以就这样被放过了... 当然,这只是我们的猜测,估计 BE 自己今天也说不清自己当时为什么这么干的了吧。

为什么arguments是类数组对象的更多相关文章

  1. 类数组对象 实参对象arguments

    先看实参对象arguments 之前对argument有点印象,知道它不是真正的数组,但也可以arguments[0]和arguments.length.今天详细的记录一下. js的默认行为:省略的实 ...

  2. (三十六)类数组对象arguments

    类数组对象:arguments 在函数调用时,我们总能见到arguments这个对象,它具体是用来干什么的呢?感觉逼格非常高呢 函数在使用时,我们总会位函数传入各种参数,arguments会将参数储存 ...

  3. 类数组对象:arguments

    在js中调用一个函数的时候,我们经常会给这个函数传递一些参数,js把传入到这个函数的全部参数存储在一个叫做arguments的东西里面,那它到底是什么呢? 一.描述 arguments 是一个对应于传 ...

  4. 类数组对象arguments 和 数组对象

    arguments并不是一个真正的数组,而是一个“类似数组(array-like)”的对象: 就像下面的这段输出,就是典型的类数组对象: {0:12, 1:23} 一.类数组 VS 数组 相同点: 都 ...

  5. 浅谈js的类数组对象arguments

    类数组对象:arguments总所周知,js是一门相当灵活的语言.当我们在js中在调用一个函数的时候,我们经常会给这个函数传递一些参数,js把传入到这个函数的全部参数存储在一个叫做arguments的 ...

  6. 类数组对象与arguments

    类数组对象 所谓的类数组对象: 拥有一个 length 属性和若干索引属性的对象 举个例子: var array = ['name', 'age', 'sex']; var arrayLike = { ...

  7. 类数组对象与 arguments

    类数组对象:拥有一个 length 属性和若干索引属性的对象 var array = ['name', 'age', 'sex']; var arrayLike = { 0: 'name', 1: ' ...

  8. 简述JavaScript对象、数组对象与类数组对象

    问题引出 在上图给出的文档中,用JavaScript获取那个a标签,要用什么办法呢?相信第一反应一定是使用document.getElementsByTagName('a')[0]来获取.同样的,在使 ...

  9. [Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法

    前面有几条都讲过关于Array.prototype的标准方法.这些标准方法被设计成其他对象可复用的方法,即使这些对象并没有继承Array. arguments对象 在22条中提到的函数argument ...

随机推荐

  1. Struts2学习笔记整理(四)

    Struts2上传下载 文件上传 如果想使用HTML表单上传文件(一个或多个),那么必须把HTML表单的enctype属性设置成multipart/form-data,且method=post, 且使 ...

  2. License友好的前端组件合集

    在做Web开发过程中,不可避免的会用到各种UI组件.通常,我们并不会需要什么组件,都去自己开发的,网上有那么多好用的,我们为什么要自己造轮子呢?我通常只会在网上找不到合适的组件时,才会去自己开发一套. ...

  3. Intellij idea 复制粘贴查找快捷键失效

    遇到此问题,竟不能复制, 发现原因,是因为勾选了Vim模式, Tools,Vim Emulator,前面会有一个√,取消即可,如图: 我的是这个原因,复制粘贴快捷键失效,也有可能历史粘贴板的深度不够 ...

  4. HTML基础教程-段落

    HTML 段落 段落是通过 <p> 标签定义的. <p>This is a paragraph</p> <p>This is another parag ...

  5. h5 喜帖

    地址:http://139.196.27.185:8088/ 因为国庆结婚,需要邀请亲朋好友,网上找了些电子请帖,但大都要收费,贵的还有好几百,有的效果还不太好.于是花了些时间自己写了一个. 就是sw ...

  6. Spring基础篇——DI和AOP初识

    前言 作为从事java开发的码农,Spring的重要性不言而喻,你可能每天都在和Spring框架打交道.Spring恰如其名的,给java应用程序的开发带了春天般的舒爽感觉.Spring,可以说是任何 ...

  7. Pashmak and Flowers

    Pashmak decided to give Parmida a pair of flowers from the garden. There are nflowers in the garden ...

  8. openstack操作之一 命令行

    在openstack环境中提供了多种操作虚拟机的方法,有最简单直接的dashborad界面,有不直观但高效的命令行,还有进阶版的postman调用openstack restfulapi和命令行中使用 ...

  9. CentOS7.4 chrony时间同步服务器部署(替代NTPD)

    Chrony是一个开源的自由软件,它能保持系统时钟与时钟服务器(NTP)同步,让时间保持精确. 它由两个程序组成:chronyd和chronyc. chronyd是一个后台运行的守护进程,用于调整内核 ...

  10. Nginx (一) 认识Nginx并进行安装

    Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.Nginx是由Igor Sysoev为俄罗斯访问量第二的R ...