Array.prototype.findLast() and findLastIndex()
ECMAScript 13 introduced two new array methods: Array.prototype.findLast()
and Array.prototype.findLastIndex()
. These methods address the inefficiency of traversing an array from front to back when trying to retrieve the last matching element, providing developers with more flexible array manipulation capabilities.
Array.prototype.findLast()
Method
The findLast()
method searches the array from the end to the beginning and returns the first element that satisfies the condition. If no matching element is found, it returns undefined
. Its syntax is similar to the find()
method:
arr.findLast(callback(element[, index[, array]])[, thisArg])
Basic Usage Example
const numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
// Find the last element greater than 3
const lastGreaterThanThree = numbers.findLast(num => num > 3);
console.log(lastGreaterThanThree); // Output: 4
// Find the last element equal to 10 (does not exist)
const lastEqualsTen = numbers.findLast(num => num === 10);
console.log(lastEqualsTen); // Output: undefined
Complex Object Lookup
const users = [
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Charlie', active: true },
{ id: 4, name: 'David', active: false },
{ id: 5, name: 'Eve', active: true }
];
// Find the last user with active set to true
const lastActiveUser = users.findLast(user => user.active);
console.log(lastActiveUser);
// Output: { id: 5, name: 'Eve', active: true }
Performance Considerations
When working with large arrays, findLast()
is more efficient than reversing the array and then using find()
:
// Inefficient approach
const reversedFind = [...largeArray].reverse().find(callback);
// Efficient approach
const optimizedFind = largeArray.findLast(callback);
Array.prototype.findLastIndex()
Method
The findLastIndex()
method is similar to findLast()
, but it returns the index of the element instead of the element itself. If no matching element is found, it returns -1.
arr.findLastIndex(callback(element[, index[, array]])[, thisArg])
Basic Usage Example
const numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
// Find the index of the last element greater than 3
const lastIndexGreaterThanThree = numbers.findLastIndex(num => num > 3);
console.log(lastIndexGreaterThanThree); // Output: 5
// Find the index of the last element equal to 10 (does not exist)
const lastIndexEqualsTen = numbers.findLastIndex(num => num === 10);
console.log(lastIndexEqualsTen); // Output: -1
Practical Application Scenario
const logEntries = [
{ timestamp: '2023-01-01', event: 'login', success: true },
{ timestamp: '2023-01-02', event: 'purchase', success: true },
{ timestamp: '2023-01-03', event: 'login', success: false },
{ timestamp: '2023-01-04', event: 'logout', success: true },
{ timestamp: '2023-01-05', event: 'login', success: true }
];
// Find the index of the last failed login
const lastFailedLoginIndex = logEntries.findLastIndex(
entry => entry.event === 'login' && !entry.success
);
console.log(lastFailedLoginIndex); // Output: 2
Comparison with Existing Methods
Differences from find()
and findIndex()
const array = ['a', 'b', 'c', 'b', 'a'];
console.log(array.find(item => item === 'b')); // 'b' (first)
console.log(array.findLast(item => item === 'b')); // 'b' (last)
console.log(array.findIndex(item => item === 'b')); // 1
console.log(array.findLastIndex(item => item === 'b')); // 3
Differences from lastIndexOf()
const array = [1, 2, 3, 2, 1];
// lastIndexOf can only perform simple value comparisons
console.log(array.lastIndexOf(2)); // 3
// findLastIndex can handle complex conditions
console.log(array.findLastIndex(x => x > 1 && x < 3)); // 3
Advanced Usage
Usage in Method Chaining
const products = [
{ id: 1, name: 'Laptop', price: 999, inStock: true },
{ id: 2, name: 'Phone', price: 699, inStock: false },
{ id: 3, name: 'Tablet', price: 499, inStock: true },
{ id: 4, name: 'Monitor', price: 299, inStock: true },
{ id: 5, name: 'Keyboard', price: 99, inStock: false }
];
// Get the last in-stock product priced below 500
const lastAffordableInStock = products
.filter(product => product.inStock)
.findLast(product => product.price < 500);
console.log(lastAffordableInStock);
// Output: { id: 4, name: 'Monitor', price: 299, inStock: true }
Interaction with Sparse Arrays
const sparseArray = [1, , 3, , 5, , 7];
// Find the last existing element
const lastExisting = sparseArray.findLast(x => x !== undefined);
console.log(lastExisting); // 7
// Find the index of the last existing element
const lastExistingIndex = sparseArray.findLastIndex(x => x !== undefined);
console.log(lastExistingIndex); // 6
Browser Compatibility and Polyfill
Although ECMAScript 13 is a relatively new standard, these features can be polyfilled in environments that do not support them:
findLast()
Polyfill
if (!Array.prototype.findLast) {
Array.prototype.findLast = function(callback, thisArg) {
for (let i = this.length - 1; i >= 0; i--) {
if (i in this && callback.call(thisArg, this[i], i, this)) {
return this[i];
}
}
return undefined;
};
}
findLastIndex()
Polyfill
if (!Array.prototype.findLastIndex) {
Array.prototype.findLastIndex = function(callback, thisArg) {
for (let i = this.length - 1; i >= 0; i--) {
if (i in this && callback.call(thisArg, this[i], i, this)) {
return i;
}
}
return -1;
};
}
Real-World Application Examples
Finding the Last Error in Form Validation
const formFields = [
{ id: 'username', value: '', isValid: false, error: 'Username cannot be empty' },
{ id: 'password', value: '123', isValid: false, error: 'Password too short' },
{ id: 'email', value: 'test@example.com', isValid: true },
{ id: 'age', value: '25', isValid: true }
];
// Get the error message of the last invalid field
const lastErrorIndex = formFields.findLastIndex(field => !field.isValid);
if (lastErrorIndex !== -1) {
console.log(`Last error: ${formFields[lastErrorIndex].error}`);
// Output: "Last error: Password too short"
}
Detecting Recent Events in Game Development
const gameEvents = [
{ frame: 100, type: 'enemy_spawn', enemyType: 'zombie' },
{ frame: 150, type: 'player_hit', damage: 10 },
{ frame: 180, type: 'enemy_spawn', enemyType: 'skeleton' },
{ frame: 200, type: 'player_hit', damage: 15 },
{ frame: 220, type: 'powerup_collected', powerType: 'health' }
];
// Find the frame of the last player hit
const lastHitFrame = gameEvents.findLastIndex(event => event.type === 'player_hit');
console.log(`Last hit occurred at frame: ${gameEvents[lastHitFrame].frame}`);
// Output: "Last hit occurred at frame: 200"
Performance Optimization Tips
Early Termination of Traversal
Like find()
and findIndex()
, findLast()
and findLastIndex()
terminate traversal immediately upon finding the first match:
const largeArray = new Array(1000000).fill(0);
largeArray[999999] = 1;
console.time('findLast');
largeArray.findLast(x => x === 1); // Only needs to check the last element
console.timeEnd('findLast'); // Very fast
console.time('find');
largeArray.find(x => x === 1); // Needs to check all elements until the last
console.timeEnd('find'); // Much slower
Comparison with for
Loops
const array = new Array(100000).fill(0).map((_, i) => i);
// Using a for loop to find the last even number
let lastEvenFor;
console.time('for loop');
for (let i = array.length - 1; i >= 0; i--) {
if (array[i] % 2 === 0) {
lastEvenFor = array[i];
break;
}
}
console.timeEnd('for loop');
// Using findLast to find the last even number
console.time('findLast');
const lastEven = array.findLast(x => x % 2 === 0);
console.timeEnd('findLast');
// Both approaches have similar performance, but findLast is more concise
Comparison with Similar Features in Other Languages
JavaScript vs. Python
# Python equivalent
lst = [1, 2, 3, 2, 1]
last_even = next((x for x in reversed(lst) if x % 2 == 0), None)
print(last_even) # Output: 2
JavaScript vs. C#
// C# equivalent
var list = new List<int> { 1, 2, 3, 2, 1 };
var lastEven = list.FindLast(x => x % 2 == 0);
Console.WriteLine(lastEven); // Output: 2
Usage in TypeScript
TypeScript already provides type definitions for these new methods:
interface Array<T> {
findLast<S extends T>(
predicate: (value: T, index: number, array: T[]) => value is S,
thisArg?: any
): S | undefined;
findLast(
predicate: (value: T, index: number, array: T[]) => unknown,
thisArg?: any
): T | undefined;
findLastIndex(
predicate: (value: T, index: number, array: T[]) => unknown,
thisArg?: any
): number;
}
// Usage example
const numbers: number[] = [1, 2, 3, 4, 5];
const lastEven = numbers.findLast((n): n is number => n % 2 === 0);
console.log(lastEven); // 4
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:瑞幸咖啡的私域流量运营