素材牛VIP会员
JS为什么可以用{length:20}来伪装成为20个undefined元素的arguments
 18***30  分类:Node.js  人气:754  回帖:3  发布于6年前 收藏

看Vue的官方文档的时候看到这么个奇技淫巧.
就是通过{length:20}来伪装成为包含了20个undefined元素的数组arguments.
举个例子的话就是这样:

function returnArguments(){
    return arguments;
}
var args = returnArguments.apply(null,{length:20})
console.log(args);
//[undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]

这背后的原理是怎样的? apply函数在将第二个参数转变为arguments时做了怎样的处理?
要知道new Array(20)或者[].length=20都不会往数组里面添加任何的内容的,
new Array(20).forEach(()=>console.log(1))也是不会打印任何内容的.
而为什么上述Vue官网的使用中却能得到真正填充了undefined的数组?

讨论这个帖子(3)垃圾回帖将一律封号处理……

Lv3 码奴
踏***e Web前端工程师 6年前#1

其实我想知道 伪装20个参数在,什么场景下有这个需求

Lv5 码农
那***美 CEO 6年前#2

题主认为我没有解释原因。看来我应该把格式搞清晰一点,所以修改一下,分个段

先说点与问题无关但对使用会有影响的

如果你检查一下 returnArguments() 的返回值,你会发现那不是一个数组

function returnArguments() {
    return arguments;
}
var a1 = returnArguments.apply(null, { length: 20 });
console.log(Array.isArray(a1));

// 输出 false

arguments 是一个伪数组,并不是真正的数组。如果用 es6,可以这样得到数组

function createArray(...args) {
    return args;
}
var a2 = createArray.apply(null, { length: 20 });
console.log(Array.isArray(a2));

// 输出 true

不过,一般来说,我会使用这个方法

var a3 = Array.apply(null, { length: 20 });

现在分析产生空数组的原因

arguments 是个伪数据,但打印出来跟数组的表现一样。下面的分析基于可以产生真正数组的 Array(),但使用 returnArguments() 的原理是一样的。

首先,描述一下不用 apply() 的方式

原理其实很简单,就拿 Array() 来说,它接受若干个参数,并把这些参数组成一个数组返回出来,所以如果我们想把 1,2,3,4,5 变成数组可以这样

var a = Array(1,2,3,4,5);

进一步,用 apply(),但直接给数组作为参数

改写成 apply() 方式就是

Array.apply(null, [1,2,3,4,5]);

接下来,把直接数组改为伪数组(作为参数)

apply() 的第二个参数,可以是一个伪数组,所以可以传入这样一个数据来代替 [1,2,3,4,5]

var data = {
    length: 5,
    "0": 1,
    "1": 2,
    "2": 3,
    "3": 4,
    "4": 5
};

最后,仅构造伪数组的关键信息 length

现在我们只需要生成一个指定长度的数组,而不关心数据(undefined),所以这个作为伪数组的参数就可以写成

{ length: 5 }

即产生长度为5的数据可以用 Array.apply 这样生成

var r = Array.apply(null, { length: 5 });

扩展:如果要不是全 undefined 的应该怎么做

如果需要指定从 1 开始的 5 个数作为元素,可以这样

var list = Array.apply(null, { length: 5}).map((v, index) => index + 1);
Lv5 码农
黑***黑 Web前端工程师 6年前#3

直接贴地址吧:
apply 工作步骤
http://ecma-international.org...
[[Get]] (P) 工作步骤
http://ecma-international.org...
希望可以帮助题主。
PS:一些不是特别明白的问题可以到ECMA上面看一下引擎的具体实现步骤,
有的时候会有意想不到的收获.

 文明上网,理性发言!   😉 阿里云幸运券,戳我领取