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)
可以使一些類數組對象轉換為對象,進而使用數組的方法來解決一些問題。