[].slice.call(arguments) 转数组的原理

1
2
3
4
5
function test(){
console.log([].slice.call(arguments))
}

test(1,2,3,4) // [1,2,3,4]

我们经常可以看到一些文档或者比人的源码之中用这种方式把arguments转化为数组,但是为什么可以这样子操作呢,现在我们可以看一下Array.prototype.slice 他的实现原理是怎样的。

slice 的原理

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
29
30
31
32
33
34

Array.prototype.slice = function(begin, end) {
end = (typeof end !== 'undefined') ? end : this.length;

var i,
cloned = [],
size,
len = this.length;

var start = begin || 0;
start = (start >= 0) ? start : Math.max(0, len + start);

var upTo = (typeof end == 'number') ? Math.min(end, len) : len;
if (end < 0) {
upTo = len + end;
}

size = upTo - start;

if (size > 0) {
cloned = new Array(size);
if (this.charAt) {
for (i = 0; i < size; i++) {
cloned[i] = this.charAt(start + i);
}
} else {
for (i = 0; i < size; i++) {
cloned[i] = this[start + i];
}
}
}

return cloned;
};

我们可以到 slice 其实是在用 this 访问对象的属性,通过callarguments绑定到this上,以此可以遍历出 arguments 的全部参数。

通过 slice 的底层原理我们也可以看出,如果我们传一个字符串进去,会把字符串转化为数组

1
[].slice.call('12345'); // [1,2,3,4,5]

ES6的新方法

ES6 给 Array 新加了一个方法,我们也可以通过他把 arguments 转化为数组。

1
2
3
4
5
6
7
8

Array.from({length:2,0:1,1,2}) // [1,2]

function test(){
console.log(Array.from(arguments))
}

test(1,2,3);// [1,2,3]

相比于 slicefrom 更强大一点,from 还可以将带有遍历器属性[Symbol.iterator]的对象转化为数组

例如我们可以这样操作

1
2
3
4
5
6
7
8

var test = {}
test[Symbol.iterator] = function *(){
yield 1;
yield 2;
yield 3;
}
Array.from(test);// [1,2,3]