整篇會分成以下幾個部分:
at
這個 method 的全寫應該是 Array.prototype.at
,有興趣可以看 Day 2 的介紹,這邊會直接使用 at()
作為替代。
Array method 有不少會使用到 callback function,如果尚不熟悉的話,可以看 Day 2 的介紹。
範例使用的 callback 都會使用箭頭函式做介紹,如果尚不熟悉的話可以參考 MDN 的介紹。
最後會透過分析 ECMAScript 來驗證是否有吻合,如果覺得 ECMAScript 有點艱澀難懂,我們在 Day 4 、Day 5 有介紹其相關術語可以幫助閱讀。
當你就是不想使用 [arr.length - N]
或 Array.prototype.slice
的時候。
at
讓你可以使用正負數的索引 (index) 來取得元素,如果沒有跟索引相對應的元素則回傳 undefined
你同時可能會想到的其他方法:
find()
- 找到第 1 個符合條件的 elementfindLast()
- 從陣列結尾開始,找到第 1 個符合條件的 elementfilter()
- 回傳一個包含所有符合條件的元素陣列slice()
- 回傳一個指定區間的新陣列at(index)
at()
只接受一個參數又稱為索引 (index)
index
它可以是一個正數或負數的值 (包含小數),它代表著在陣列裡的相對位置 (relative index)。
0
開始-1
開始回傳跟索引 (index) 相對應的陣列元素,如果沒有則回傳 undefined
。
不會變動到原陣列
const names = ['Damien', 'Collin', 'Brad', 'Emma', 'Anita', 'Sepncer']
console.log(names.at(1)) // 'Collin'
console.log(names.at(-1)) // 'Spencer'
console.log(names.at(3)) // 'Emma'
console.log(names.at(-3)) // 'Emma'
0
const names = ['Damien', 'Collin', 'Brad', 'Emma', 'Anita', 'Sepncer']
console.log(names.at(1.2)) // 'Collin'
console.log(names.at(-1.2)) // 'Spencer'
console.log(names.at(3.6)) // 'Emma'
console.log(names.at(-3.6)) // 'Emma'
console.log(names.at(-0.5)) // 'Damien'
at()
傳入的索引值也可以是小數,其轉換的方式不是單純使用 floor()
,請參考注意事項說明的部分const names = ['Damien', 'Collin', 'Brad', 'Emma', 'Anita', 'Sepncer']
console.log(names.at(6)) // undefined
console.log(name.at(-7)) // undefined
undefined
at()
vs length
vs slice()
const names = ['Damien', 'Collin', 'Brad', 'Emma', 'Anita', 'Sepncer']
console.log(names.at(-1)) // 'Spencer'
console.log(names[names.length - 1]) // 'Spencer'
console.log(names.slice(-1)[0]) // 'Spencer'
at()
顯得簡潔且直覺arr[-1]
), 因為 -1
是一個合法的物件屬性名稱,例如以下:const names = {
0: 'Damien',
1: 'Collin',
'-1': 'Spencer'
}
console.log(names[-1]) // 'Spencer'
[-1]
的陣列取值方式會取得這個陣列的 -1
屬性,但實際上陣列不會有負數的索引,所以最終會回傳 undefined
at()
傳入的索引可以是一個小數,這個索引值會被轉換成一個整數,但請注意其轉換的方式,可參考 ToIntegerOrInfinity 這個 abstract operation 跟範例的 Example 2Array.prototype.at(index)
this
轉型成一個 object 後指派給 O
O
的長度並指派給 len
index
轉成一個整數後指派給 relativeIndex
relativeIndex
≥ 0relativeIndex
指派給 k
len
+ relativeIndex
的結果指派給 k
k
< 0 或 k
≥ len
,回傳 undefined
k
轉成 Number 再轉成 String 後,利用其結果找出 O
相對應屬性的值並回傳ToIntegerOrInfinity
讓 index
是小數仍然可以正常使用,而且因為它在轉換的過程使用了絕對值,導致轉成整數的結果可能會跟預期的不一樣,可以參考 Example 2relativeIndex
如果 ≥ 0,則不做任何改變,並直接使用其取值relativeIndex
< 0 時,就會再加上 len
後取值,正是這個步驟讓我們可以對陣列使用負數取值?
的地方代表有可能會丟出錯誤,所以整個演算法有 4 處有機會丟出錯誤,例如步驟 3 的 ToIntegerOrInfinity()
,當你傳入 Symbol 或 BigInt 即會從內部的 ToNumber()
丟出一個 TypeError 的錯誤,我們可以來驗證一下!
,則代表這個 abstract operation 絕對不會丟出錯誤,例如步驟 7 的 ToString()
它會在參數是一個 Symbol 時丟出一個 TypeError,但我們確定丟進去的是一個 Number (F(k)
),因此不會有丟出錯誤的可能JavaScript 不像其他語言 (Python) 有支援從陣列結尾計算索引取值,因此必須透過 at()
來達成這個功能,同時也讓程式碼更加簡潔。
但需要注意傳進去的索引如果是小數會自動被轉換,而不是直接丟出錯誤,有時候可能會產生非預期狀況,請小心使用。
最後,希望大家可以開心地使用各種咩色,體驗它帶給你的便利,祝大家歸剛沒煩惱。
總算不用寫這種醜東西了
var a = [1, 2, 3, 4, 5]
a[a.length - 1]
真的, 最討厭寫醜東西了!