Array.prototype.slice.call(arguments) 到底做了什麼?

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()

來使用一個方法的時候,object自動成爲當前方法methodthis值,所以當像如下代碼那樣使用slice()方法的時候:

[1,2,3].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)可以使一些類數組對象轉換爲對象,從而使用數組的方法來解決一些問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章