iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0
Modern Web

咩色用得好,歸剛沒煩惱 - 從 ECMAScript 偷窺 JavaScript Array method系列 第 14

Day14 咩色用得好 - Array.prototype.some (沒事沒事,有就好了)

  • 分享至 

  • xImage
  •  

Abstract

我是阿傑,我有一陣子很迷戀設定每月目標,給自己立 flag,只要達標我就會犒賞自己,例如這樣:

14.1

很明顯的,我只有追劇達標!但人腦很奇妙,總是只看到美好的一面:「哇,我比上個月進步了,至少有達到一項目標,以前連一項都達不到呢,我覺得自己很棒!」,所以我點開了 Apple 官網把 AirPods Pro 加到了購物車。

《考試 5 科只有 1 科及格》
媽媽:「唉...」
阿嬤:「沒關係啦,只要有 1 科及格就好啦!」

我們會分成以下幾個部分介紹:

  • 使用時機
  • 語法
  • 說明
  • 範例
  • 注意事項
  • ECMAScript
  • 結論

使用時機

當你想要知道陣列中是否至少有 1 個元素符合測試條件,即可使用。

什麼意思呢?例如我們需要知道這個陣列是否有包含 AJay 這個名字:

['Anita', 'Alex', 'AJay', 'Alejo'] => true 

如果至少有 1 個元素通過測試則回傳 true,否則回傳 false


語法

  • Arrow function (直接定義箭頭函式)
some((element, index, array) => {
	/* 測試條件 */
* })
  • callback (直接傳入回呼函式)
some(callbackFn, thisArg)
  • Inline Callback (直接定義匿名函式)
some(function(element, index, array){
	/* 測試條件 */ 
}, thisArg)

參數

some() 的第 1 個參數為 callback, 第 2 個參數為可選的 (optional) thisArg

callback

這個 callback 又稱為 testing functionpredicate,顧名思義它會被拿來測試某些條件,再準確一點應該稱作斷言 (assert) ,因為它最後回傳的值會被強制轉換成布林值 (truefalse)!

當這個 callback 被呼叫時會帶入 elementindexarray 三個參數。

some() 會按照陣列元素的順序依次 (升冪) 呼叫這個 callback,直到這個 callback 回傳 true 或當陣列元素已被遍歷完畢即停止,換句話說,如果這個陣列有 5 個元素,那這個 callback 最多會被呼叫 5 次。

  • element
    陣列當前的元素 (element),callback 的第 1 個參數,為 some() 當前遍歷到的元素,也就表示 element 會依陣列的順序動態變化。

  • index
    陣列當前元素的索引值 (index),callback 的第 2 個參數,為 some() 當前遍歷到的元素其索引值,也就表示 index 會依陣列的順序動態變化。

  • array
    呼叫 some() 的陣列本身 (被遍歷的陣列本身), callback 的第 3 個參數,不論 some() 當下遍歷到哪個元素上, array 都會指向被遍歷的陣列本身,也就是呼叫 some() 的陣列本身。

thisArg

some() 的第 2 個選擇性參數,它會被傳入 callback 並作為其 this 的值,否則就會是 undefined

請注意,如果 callback 使用箭頭函式的話則沒有作用!

可以參考範例的 Example - 4 寫法。

Return Value

只要陣列中有一個元素符合測試條件就馬上回傳 true,否則則回傳 false

Mutability

不會變動到原陣列


說明

some() 會遍歷每個元素並呼叫 callback 來做條件測試,只要有 1 個元素通過測試就會立刻回傳 true 並終止運行,如果全部都沒有通過測試則回傳 false


範例

Example 1 - 基礎用法

const names = ['Anita', 'Alex', 'Alexsander', 'Alejo']

const isAlexThere = names.some(name => name === 'Alex')

console.log(isAlexThere)
// true

names 至少有一個元素為 Alex 時,即回傳 true

Example 2 - 使用 index 參數

const names = ['Anita', 'Alex', 'Alexsander', 'Alejo']

const result = names.some((name, index) => name === 'Alex' && index === 2)

console.log(result)
// false

name 至少有一個元素為 Alex 且索引為 2 時,回傳 true

Example 3 - 陣列包含多個物件

const foods = [
	{ name: 'kiwi', price: 120, expired: false},
	{ name: 'oyster', price: 250, expired: false },
	{ name: 'milk', price: 180, expired: true },
	{ name: 'cherry', price: 300, expired: false },
	{ name: 'mango', price: 420, expired: false }
]

const isAnyFoodExpired = foods.some(food => food.expired)

console.log(isAnyFoodExpired)
// true

foods 至少有一個元素的 expiredtrue 時,即回傳 true

Example 4 - 使用 thisArg 參數

const names = ['Anita', 'Alex', 'Alexsander', 'Alejo']

const ages = [25, 18, 44, 32]

const result = names.some(function (name, index) {
	return name.length > 6 && this[index] > 30
},ages)

console.log(result)
// true

names 至少有一個元素的長度 > 6 跟 ages 至少有一個元素 > 30時,回傳 true


注意事項

雖然 some() 會自動對回傳的值做布林轉換,但可以考慮讓 callback 直接回傳布林值,這樣比較不會有轉型上的失誤,閱讀起來也較直覺。

請注意 callback 定義時的參數順序,依序應為 elementindexarray,假設你只想使用 index 而不使用 element,你仍需定義 element,可以增加底線以利閱讀,例如這樣:

array.some((_element, index) => { /* ... */ })

有一點值得注意的是,雖然 some() 不會變動到原陣列,但我們傳進去的 callback 卻有可能 ,而陣列元素被遍歷的範圍在第一次呼叫 callback 前就已經確立好了 (也就是 some() 被呼叫後但 callback 尚未被呼叫),因此有可能會發生以下的狀況:

  • 在這之後才被添加 (appended) 進去的元素不會被 callback 遍歷到
  • 如果原先存在的元素被變動到了, 那當 callback 遍歷到此元素時會使用它最新的值,而非原先的值
  • 如果尚未被遍歷到的元素被刪除了,那它將不會被遍歷到

上述這種高併發 (concurrent) 的更動會導致程式碼非常難以閱讀,非常不建議使用 (除非有特殊的情境)。


ECMAScript

14.2

some() 的演算法並沒有要求呼叫它的一定要是一個陣列,可以從步驟 1 跟 Note 2 得知,為了方便解釋,這邊一律使用陣列來說明。

演算法的前 3 個步驟都是用來做一些前置處理,包括轉型、確認長度、確認參數是否為一個 function 等...。

步驟 5 會看到遍歷的次數在 callback 第 1 次呼叫前就已經決定好了,而且每次的 callback 呼叫前都會先檢查相對應的屬性 (陣列索引) 是否存在, 如果不存在則不會呼叫,驗證了上面注意事項對高併發之 callback 的說明。

步驟 5 - c -iii 會看到當 callback 回傳的值為 true 時,some() 便回傳 true 並立即終止運行,驗證了上面的說明。

出現 ? 的地方代表有可能會丟出錯誤,所以整個演算法有 5 處有機會丟出錯誤,例如步驟 1 的 ToObject(),當你傳入 Undefined 或 Null 即會丟出一個 TypeError 的錯誤。

如果出現 ! 則代表這個 abstract operation 絕對不會丟出錯誤,例如步驟 5 - a 的 ToString() 它會在參數是一個 Symbol 時丟出一個 TypeError,但我們確定丟進去的是一個 Number (F(k)),因此不會有丟出錯誤的可能。

我們來驗證一下 some() 是否如規範所說的被做成通用的一個方法:

14.3


結論

some()every() 用途類似,差別在於 some() 只要有 1 個通過測試就會回傳 true

some() 可能是相對較冷門的咩色,也可以被很多方法取代,那為什麼要使用它?調用我們 Day 1 提到的 - 乾淨、直覺、可讀性高!

最後,希望大家可以開心地使用各種咩色,體驗它帶給你的便利,祝大家歸剛沒煩惱。


參考資源


上一篇
Day 13 咩色用得好 - Array.prototype.reduce (新手摧毀者)
下一篇
Day15 咩色用得好 - Array.prototype.fill (將陣列變成你想要的形狀)
系列文
咩色用得好,歸剛沒煩惱 - 從 ECMAScript 偷窺 JavaScript Array method30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言