什麼是Array-like?
偽陣列物件的特性、轉化陣列的相關方法
說明
在學習的時候,有時會遇到某東西被稱為Array-like,並且要注意不要錯把他當成陣列等等的,後來知道其實全名為Array-like object,顧名思義是一個很像是陣列的物件,聽起來很像廢話,不過既然是很像陣列,代表這個物件也具有部份陣列的特性。
特性
- 可以使用索引值取值
- 本身不具有陣列方法,但可以透過Array.prototype直接移植陣列方法做使用
- 有length屬性
- 可遍歷
常見的Array-like Object包括:
- 函數內部的 arguments
- DOM 對象列表(比如 document.querySelectorAll 得到的lists)
製作一個Array-like Object
若我們要自己製作一個Array-like Object要怎麼做呢?
- 屬性要為索引(數字)值
- 一定要有length屬性存在
參考來自於前輩的範例:
與陣列之間的關係
如果有注意到那個push,事實上他是完全可以運作的,這也是我覺得最有趣的部份之一,console後的結果見下圖:
不是說他不是陣列嗎?為什麼可以使用陣列的push?
原因來自於push被實作的方式,以下借用
沒辦法完全看懂無所謂,重點在於,push的必要參數就只有length屬性而已,於是只要有length,其實都可以借用Array.prototype.push來使用。
除了push,絕大部分的陣列方法都可以這樣被借用,像是slice, pop...等。
借用方式有兩種:
- 按照前面的方式,為Object增加新屬性,其值設定為Array.prototype.<method>。
- 透過apply, call等重新綁定this的方法直接呼叫Array.prototype.<method>,並指定this要綁定的對象為Array-like Object
Array.prototype.<method>.call(<objName>, <method's argument1>, ...)
舉例來說,借用最一開始的範例,想要直接使用push方法又不想要賦值新的屬性的話,可以這樣做。
Array.prototype.push.call(obj, 'd')
這樣後續console結果跟圖1是一模一樣的~。
轉化真●陣列的方法
那要如何將Array-like Object轉換為真陣列呢?
有三種方法是我知道的:
- 遍歷每個屬性並貼到新的陣列裡面
- 透過Array.prototype.slice.call將整個陣列切割並複製
- 使用Array.from產生新的陣列出來
底下幾個console是為了測試某變數是否為陣列,包括是否為Array及Object的實例、是否能使用索引值取值、是否包含forEach函式等。
那差不多就這樣啦~~
參考資料