JS 數組相關的迴圈函數,用得挺多,所以有些坑還是要去踩一下,先來看一道面試題。 註意: 下麵提到的不改變原數組僅針對基本數據類型。 面試題 模擬實現數組的 map 函數。 心中有答案了嗎?我的答案放在最後。 map( callback( cur, index, arr ), thisArg ) m ...
JS 數組相關的迴圈函數,用得挺多,所以有些坑還是要去踩一下,先來看一道面試題。
註意:下麵提到的不改變原數組僅針對基本數據類型。
面試題
模擬實現數組的 map 函數。
心中有答案了嗎?我的答案放在最後。
map( callback( cur, index, arr ), thisArg )
map 方法創建一個新數組,其結果是該數組中的每個元素都調用一個提供的函數後返回的結果。
map 不改變原數組(可以在 callback 執行時改變原數組)
let a = [1, 2, 3] let b = a.map(item => item*2) // 不改變原數組 a // [1, 2, 3] b // [2, 4, 6] // 在 callback 執行時改變原數組 a.map((cur, i, arr) => arr[i] *= 2) a // [2, 4, 6]
沒有 return 時,返回
undefined
let c = a.map((cur, i, arr) => arr[i] *= 2) c // [undefined, undefined, undefined]
原數組中新增加的元素不會被 callback 訪問
let a = [1, 2, 3] let b = a.map((cur, i, arr) => { arr.push(arr.length + 1) return cur*2 }) b // [2, 4, 6] a // [1, 2, 3, 4, 5, 6]
filter( callback( cur, index, arr ), thisArg )
filter 方法創建一個新數組, 其包含通過所提供函數實現的測試的所有元素。
這個沒什麼好說的,filter 只返回過濾後的新數組,依然不會改變原數組
let a = [1, 2, 3]
let b = a.filter(item => item % 2 == 0)
a // [1, 2, 3]
b // [2]
需要註意的是,儘量不要在 filter 中直接return item
。
/* 一般情況是沒問題的 */
let a = [1, 2, 3]
let b = a.filter(item => item)
a // [1, 2, 3]
b // [1, 2, 3]
/* false、0、undefined、null */
let c = [true, false, 0, undefined, null]
let d = c.filter(item => item)
c // [true, false, 0, undefined, null]
d // [true]
一般情況下直接return item
是沒問題的,但遇到false、0、undefined、null
這幾個特殊值時,就會出問題。因為 filter 是根據return
的值來判斷返回的新數組是否要添加遍歷到的原數組索引值,而不是直接在新數組中添加return
的值。
簡單來說,就是 filter 中的 callback 的 return 應該返回一個 boolean 值,true 即滿足過濾條件,false 則不滿足過濾條件。
forEach( callback( cur, index, arr ), thisArg )
forEach 方法對數組的每個元素執行一次提供的函數。
forEach 無法中斷,需要中斷的則表明:不應該使用 forEach。當然,使用 try、catch 是可以實現中斷的,但不推薦。
let a = [1, 2, 3] try { a.forEach(item => { console.log(item) if (item % 2 == 0) throw new Error('hhh') }) } catch (e) { console.log('中斷') } /* 1 2 中斷 */
forEach 也是不會改變原數組的
let a = [1, 2, 3] a.forEach(item => item*2) a // [1, 2, 3]
every( callback( cur, index, arr ), thisArg )
every 方法測試數組的所有元素是否都通過了指定函數的測試。
這個沒什麼好說的,但 every 和 some 都有個坑。
坑:空數組調用 every 會返回true
。
// 返回了 true
[].every(item => item > 0) // true
some( callback( cur, index, arr ), thisArg )
some 方法測試是否至少有一個元素通過由提供的函數實現的測試。
坑:空數組調用 some 會返回false
。
// 和 every 相反,這裡返回了 false
[].some(item => item > 0) // false
reduce( callback( prev, cur, index, arr ), initVal )
reduce 方法對數組中的每個元素執行一個由您提供的reducer函數(升序執行),將其結果彙總為單個返回值。
如果沒有提供
initVal
,reduce 會取數組中的第一個值為prev
, 然後從數組索引 1 開始執行 callback,跳過第一個索引。如果提供initlVal
,從索引 0 開始,prev
為initVal
。如果數組為空且沒有提供
initVal
會報錯。[].reduce((prev, cur)=> cur) // TypeError
實現 map 函數
Array.prototype._map = function(callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError(`${callback} is not a function`)
}
let res = []
for (let i=0; i<this.length; i++) {
res.push(callback.call(thisArg, this[i], i, this))
}
return res
}