类数组对象转换为数组对象的几种方法

前言

我们都知道,在 JavaScript 中,函数的参数 arguments 对象只是一个 类数组(Array-like) 对象,而不是真正的数组。那么如果我们想把它变成一个真正的数组对象,该怎么做呢?

下面就以 arguments 为例,总结几种类数组对象转换为数组对象的办法。

原始法

最简单粗暴的办法,莫过于把 arguments 对象遍历,再放到一个空数组对象里。如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function listA() {
let arr = [];
for(let i = 0, len = arguments.length; i < len; i++) {
arr.push(arguments[i]);
}
return arr;
}
function listB() {
let arr = [];
for(let i = 0, len = arguments.length; i < len; i++) {
arr[i] = arguments[i]; //据说比上一种方式快
}
return arr;
}
function listC() {
let arr = [];
//利用 ES6 的 for...of 遍历类数组对象
for(let item of arguments) {
arr.push(item);
}
return arr;
}
listA(2, 6, 9, 3); //[2, 6, 9, 3]
listB(2, 6, 9, 3); //[2, 6, 9, 3]
listC(2, 6, 9, 3); //[2, 6, 9, 3]

Array.prototype.slice() 法

Array.prototype.slice() 方法的常规用法,是将数组的一部分进行浅复制, 返回从开始到结束(不包括结束)选择的新数组对象。

除了上面这种用法,slice() 方法也可用于将一个类数组(Array-like)对象/集合转换成一个数组。我们只需将该方法绑定到需要转换的对象上。如下所示:

1
2
3
4
5
6
7
8
9
10
function listA() {
return Array.prototype.slice.call(arguments);
}
function listB() {
return Array.prototype.slice.apply(arguments);
}
listA(2, 6, 9, 3); //[2, 6, 9, 3]
listB(2, 6, 9, 3); //[2, 6, 9, 3]

或者你也可以用 [].slice 来代替冗长的 Array.prototype.slice

1
2
3
4
5
6
7
8
9
10
function listC() {
return [].slice.call(arguments);
}
function listD() {
return [].slice.apply(arguments);
}
listC(2, 6, 9, 3); //[2, 6, 9, 3]
listD(2, 6, 9, 3); //[2, 6, 9, 3]

Function.prototype.apply() 法

Function.prototype.apply() 方法的作用,是在指定 this 值和参数(参数以数组或类数组对象的形式存在)的情况下调用某个函数。

Array() 是一个构造函数,也就是 Function 对象的实例,所以它可以直接调用 apply() 方法,并利用该方法将类数组对象转换为数组对象。如下所示:

1
2
3
4
5
6
function list() {
return Array.apply(null, arguments);
//相当于将 arguments 对象的值一个一个传递给 Array 函数作为参数
}
list(2, 6, 9, 3); //[2, 6, 9, 3]

Array.from() 法

ES6 中新增了一个 Array.from() 方法,用于将 类数组对象可遍历(Iterable)对象 转换为真正的数组。也就是说,在 ES6 中,有 “正统” 的办法把类数组对象转换为真正的数组对象了。如下所示:

1
2
3
4
5
function list() {
return Array.from(arguments);
}
list(2, 6, 9, 3); //[2, 6, 9, 3]

扩展运算符(…)法

ES6 还新增了一种运算符, 扩展运算符,它用三个半角句号(...)来表示。

扩展运算符可以将数组对象或类数组对象转换为用逗号分隔的参数序列。因此我们可以利用这一点来将类数组对象转换为真正的数组对象,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function listA() {
return [...arguments]; //变为参数序列后直接放入数组字面量中
}
function listB() {
return new Array(...arguments);
//变为参数序列后传递给 Array() 构造函数
}
function listC() {
return Array.call(null, ...arguments);
//变为参数序列后利用 call() 方法传递给 Array() 构造函数
}
listA(2, 6, 9, 3); //[2, 6, 9, 3]
listB(2, 6, 9, 3); //[2, 6, 9, 3]
listC(2, 6, 9, 3); //[2, 6, 9, 3]

结语

以上差不多就是目前笔者所知的所有将 arguments 等类数组对象转换为真正数组对象的方法了,在实际使用中,我们可以灵活选择。

------ 本文结束 ------
坚持原创技术分享,您的支持将鼓励我继续创作!