Array.prototype.slice.call(arguments) 到底做了什么?
如题,在一些代码中我们经常会看到或者
Array.prototype.slice.call(arguments)
这段代码,那这段代码到底做了什么呢?我们就来探寻一下
[].slice.call(arguments)
问题
首先来看一段代码:
function foo() {
console.log(arguments)
console.log(Array.prototype.slice.call(arguments))
}
foo(1,2,3)
在这个
foo
函数中我们打印了
arguments
以及我们经常看到的这段代码
Array.prototype.slice.call(arguments)
,那它们的结果肯定大家都知道:
foo(1,2,3);
// {0:1,1:2,2:3,length:3}
// [1,2,3]
大概是这样的,而且我们也知道
arguments
是一个
array-like
(类数组)对象,具体解释可以在MDN查看 ,那为什么经过了上述代码之后就变成了真正的数组了呢?
具体解释
我们首先来明确一个事情,就是当你通过
来使用一个方法的时候,
object
自动成为当前方法
method
的
this
值,所以当像如下代码那样使用
slice()
方法的时候:
[1,2,3]
自动变成了
slice()
方法的
this
.这个是程序定义的,我们如果想要修改,就需要使用
call
或者
apply
或者
bind
(他们之间的区别请看todo),这里我们使用
call
来演示:
[1,2,3].slice.call([2,3,4]) //[2,3,4]
// 这样写是无意义的只是作为call的展示
那么回到问题上来,我们知道
arguments
是个类数组对象了,如果将它作为
slice()
的
this
值,程序会如何处理呢?
在这里,slice 方法会认为类数组对象已经满足它自身运行的需要(有length属性,有数字作为key的键值对),所以
slice
方法会正常运行,然后得到的结果就是返回一个真正的数组对象。
引申
如果我们将 arguments 改为其他的值,那么会发生什么呢?
Array.prototype.slice.call(123); // []
Array.prototype.slice.call("123"); // ["1", "2", "3"]
Array.prototype.slice.call(true); // []
Array.prototype.slice.call(null); // error
Array.prototype.slice.call(undefined); // error
Array.prototype.slice.call({foo:"foo",bar:"bar",length:2}); // [empty × 2]
那除了这样的方式将一个其他类型的值转化为数组还有没有其他简便的办法呢?(在函数中)
我们就可以使用 es6 中的
...rest
参数了:
function bar(...rest) {
console.log(rest)
}
bar() // []
bar(1,2,3) //[1,2,3]
// 下面的两种方式也是可行的
function baz() {
console.log(Array.from(arguments))
console.log([...arguments])
}
baz(3,4,5)
推荐在以后的函数中使用
...rest
参数来替换
arguments
局部参数。
总结
Array.prototype.slice.call(arguments)
可以使一些类数组对象转换为对象,从而使用数组的方法来解决一些问题。