JS findLast() 和findLastIndex()
CUGGZ 人气:0今天来看一个 ECMAScript 提案:findLast() 和 findLastIndex()。
提案原因
在 JavaScript 中,可以通过 find() 和 findIndex() 查找数组中的值。不过,这些方法从数组的开始进行遍历:
const array = [{v: 1}, {v: 2}, {v: 3}, {v: 4}, {v: 5}]; array.find(elem => elem.v > 3); // {v: 4} array.findIndex(elem => elem.v > 3); // 3
如果要从数组的末尾开始遍历,就必须反转数组并使用上述方法。这样做就需要一个额外的数组操作。
基本使用
幸运的是,Wenlu Wang 和 Daniel Rosenwasser 关于findLast() 和 findLastIndex() 的 ECMAScript 提案解决了这一问题。该提案的一个重要原因就是:语义。
它们的用法和find()、findIndex()类似,只不过是从后向前遍历数组,这两个方法适用于数组和类数组。
- findLast() 会返回第一个查找到的元素,如果没有找到,就会返回 undefined;
- findLastIndex() 会返回第一个查找到的元素的索引。如果没有找到,就会返回 -1;
const array = [{v: 1}, {v: 2}, {v: 3}, {v: 4}, {v: 5}]; array.findLast(elem => elem.v > 3); // {v: 5} array.findLastIndex(elem => elem.v > 3); // 4 array.findLastIndex(elem => elem.v > 5); // -1
简单实现
下面来简单实现一下这两个方法。
- findLast()
function findLast(arr, callback, thisArg) { for (let index = arr.length - 1; index >= 0; index--) { const value = arr[index]; if (callback.call(thisArg, value, index, arr)) { return value; } } return undefined; } const array = [{v: 1}, {v: 2}, {v: 3}, {v: 4}, {v: 5}]; findLast(array, elem => elem.v > 3, array) // {v: 5} findLast(array, elem => elem.v > 5, array) // -1
- findLastIndex()
function findLastIndex(arr, callback, thisArg) { for (let index = arr.length - 1; index >= 0; index--) { const value = arr[index]; if (callback.call(thisArg, value, index, arr)) { return index; } } return -1; } const array = [{v: 1}, {v: 2}, {v: 3}, {v: 4}, {v: 5}]; findLastIndex(array, elem => elem.v > 3, array) // 4 findLastIndex(array, elem => elem.v > 5, array) // -1
lodash源码
下面是 lodash 实现这两个方法的源码,供大家学习!
- findLast()
import findLastIndex from './findLastIndex.js' import isArrayLike from './isArrayLike.js' /** * This method is like `find` except that it iterates over elements of * `collection` from right to left. * * @since 2.0.0 * @category Collection * @param {Array|Object} collection The collection to inspect. * @param {Function} predicate The function invoked per iteration. * @param {number} [fromIndex=collection.length-1] The index to search from. * @returns {*} Returns the matched element, else `undefined`. * @see find, findIndex, findKey, findLastIndex, findLastKey * @example * * findLast([1, 2, 3, 4], n => n % 2 == 1) * // => 3 */ function findLast(collection, predicate, fromIndex) { let iteratee const iterable = Object(collection) if (!isArrayLike(collection)) { collection = Object.keys(collection) iteratee = predicate predicate = (key) => iteratee(iterable[key], key, iterable) } const index = findLastIndex(collection, predicate, fromIndex) return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined } export default findLast
- findLastIndex()
import baseFindIndex from './.internal/baseFindIndex.js' import toInteger from './toInteger.js' /** * This method is like `findIndex` except that it iterates over elements * of `collection` from right to left. * * @since 2.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} predicate The function invoked per iteration. * @param {number} [fromIndex=array.length-1] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @see find, findIndex, findKey, findLast, findLastKey * @example * * const users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ] * * findLastIndex(users, ({ user }) => user == 'pebbles') * // => 2 */ function findLastIndex(array, predicate, fromIndex) { const length = array == null ? 0 : array.length if (!length) { return -1 } let index = length - 1 if (fromIndex !== undefined) { index = toInteger(fromIndex) index = fromIndex < 0 ? Math.max(length + index, 0) : Math.min(index, length - 1) } return baseFindIndex(array, predicate, index, true) } export default findLastIndex
可用性
该提案目前处于第 3 阶段,提案地址:https://github.com/tc39/proposal-array-find-from-last
此外,Lodash 和 Ramda 等库为数组提供了findLast() 和 findLastIndex() 操作。
目前,在 Safari 15.4 中已经支持了这两个方法。期待更多浏览器支持这两个方法!
总结
加载全部内容