Array.prototype.find
find 方法
find
方法返回数组中第一个满足提供的测试函数的元素。否则返回 undefined
。
Array.prototype.find() - JavaScript | MDN
数组是原始值
在处理包含原始值的数组时,find
方法可以轻松定位符合条件的元素。
const numbers = [1, 2, 3, 4, 5];
const foundItem = numbers.find((item) => item > 3);
console.log(foundItem); // 输出: 4
数组引用值
对于包含引用类型的数组,find
方法返回的元素与数组中对应下标的元素引用相同。
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '张三' },
{ id: 3, name: '李四' },
{ id: 4, name: '张三' },
{ id: 5, name: '张三' },
];
const foundUser = users.find((user) => user.name === '李四');
console.log(foundUser); // 输出: { id: 3, name: '李四' }
console.log(foundUser === users[2]); // 输出: true
find 的参数
回调函数的参数
回调函数接收三个参数:
- 当前遍历的元素
- 当前元素的下标
- 当前数组
更改 this 指向
find
方法的第二个参数用于指定回调函数的 this
值。在非严格模式下,this
指向 window
;在严格模式下,如果未提供第二个参数,this
为 undefined
,与严格模式的规定保持一致。
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '张三' },
{ id: 3, name: '李四' },
{ id: 4, name: '张三' },
{ id: 5, name: '张三' },
];
const context = { a: 1 };
const foundUser = users.find(function (user, index, array) {
console.log(user, index, array);
console.log(this);
}, context);
find 返回值
find
方法的回调函数返回布尔值。第一个返回 true
的元素将作为 find
的返回值。如果没有满足条件的元素,返回 undefined
。
const numbers = [1, 2, 3, 4, 5];
const foundNumber = numbers.find(function (number) {
return number > 4;
});
console.log(foundNumber); // 输出: 5
find 遍历稀疏数组
find
方法会遍历稀疏数组中的所有索引,包括空位,并将空位视为 undefined
。
const sparseArray = Array(5);
sparseArray[0] = 1;
sparseArray[2] = 3;
const foundItem = sparseArray.find(function (item) {
console.log('遍历元素');
return false;
});
console.log(foundItem); // 输出: undefined
相比之下,forEach
、every
、some
、reduce
和 map
方法会自动忽略稀疏数组中的空位。
find 不会修改原数组
使用 find
方法不会改变原始数组中的元素。
const numbers = [1, 2, 3, 4, 5];
const foundNumber = numbers.find(function (item) {
item = item + 1;
});
console.log(numbers); // 输出: [1, 2, 3, 4, 5]
可以追加值
在回调函数中向数组追加元素,find
方法会保留最初的索引范围,防止无限查找。
const numbers = [1, 2, 3, 4, 5];
const foundNumber = numbers.find(function (item) {
numbers.push(6);
console.log(item);
});
console.log(numbers);
// 输出:
// 1
// 2
// 3
// 4
// 5
// [1, 2, 3, 4, 5, 6]
删除对应项的情况
- 使用
splice
删除元素会在数组末尾补上undefined
。 - 使用
delete
或pop
删除元素后,数组中的对应位置会被填充undefined
。
const numbers = [1, 2, 3, 4, 5];
const foundNumber = numbers.find(function (item, index) {
if (index === 0) {
numbers.splice(1, 1); // 删除第二个元素
delete numbers[2]; // 删除第四个元素
numbers.pop(); // 删除最后一个元素
}
console.log(item);
});
console.log(numbers); // 输出: [1, undefined, 3, undefined]
实现 find
以下是一个自定义实现 find
方法的示例,命名为 myFind
。通过这个示例,可以更深入地理解 find
方法的内部工作机制。
Array.prototype.myFind = function (callback, thisArg) {
if (this == null) {
throw new TypeError('"this" is null 或未定义');
}
if (typeof callback !== 'function') {
throw new TypeError('回调函数必须是函数类型');
}
const array = Object(this);
const length = array.length >>> 0;
let index = 0;
while (index < length) {
const currentValue = array[index];
if (callback.call(thisArg, currentValue, index, array)) {
return currentValue;
}
index++;
}
return undefined;
};
// 测试
const numbers = [1, 2, 3, 4, 5];
const found = numbers.myFind(function (number) {
return number > 4;
});
console.log(found); // 输出: 5
在这个实现中,我扩展了 Array.prototype
添加了一个 myFind
方法。该方法首先验证 this
是否为有效的数组对象,然后迭代数组中的元素,调用回调函数并返回第一个满足条件的元素。如果没有满足条件的元素,返回 undefined
。
通过这个示例,可以更好地理解 find
方法的工作原理,并在实际开发中根据需要自定义数组方法。
数组转类数组
在某些情况下,需要将数组转换为类数组对象。类数组对象具有数组的一些特性,如 length
属性和索引,但不具备数组的所有方法。以下是一个将数组转换为类数组对象的示例:
function makeArrayLike(arr) {
const arrayLike = {
length: arr.length,
push: Array.prototype.push,
splice: Array.prototype.splice,
};
arr.forEach((item, index) => {
arrayLike[index] = item;
});
return arrayLike;
}
const newObject = makeArrayLike(['a', 'b', 'c', 'd', 'e', 'f']);
console.log(newObject);
// 输出: { '0': 'a', '1': 'b', '2': 'c', '3': 'd', '4': 'e', '5': 'f', length: 6, push: [Function: push], splice: [Function: splice] }
在上述代码中,我定义了一个 makeArrayLike
函数,它接收一个数组并返回一个类数组对象。通过使用 forEach
方法,我将数组的每个元素赋值到类数组对象中对应的位置。
实现 fill
为了更好地理解 fill
方法的工作原理,以下是一个自定义实现 fill
方法的示例,命名为 myFill
。这个实现针对特定版本的包进行了优化。
Array.prototype.myFill = function (value, start, end) {
const fillValue = typeof value !== 'undefined' ? value : undefined;
if (this == null) {
throw new TypeError('无法将 null 或 undefined 转换为对象');
}
const obj = Object(this);
const len = obj.length >>> 0;
let startIndex = typeof start === 'undefined' ? 0 : Number(start);
startIndex = isNaN(startIndex) ? 0 : startIndex < 0 ? Math.max(len + startIndex, 0) : Math.min(startIndex, len);
let endIndex = typeof end === 'undefined' ? len : Number(end);
endIndex = isNaN(endIndex) ? len : endIndex < 0 ? Math.max(len + endIndex, 0) : Math.min(endIndex, len);
for (let i = startIndex; i < endIndex; i++) {
obj[i] = fillValue;
}
return obj;
};
// 测试
const array = [1, 2, 3, 4, 5];
const filledArray = array.myFill('a', 2, 4);
console.log(filledArray); // 输出: [1, 2, 'a', 'a', 5]
在这个实现中,我扩展了 Array.prototype
添加了一个 myFill
方法。该方法首先验证 this
是否为有效的数组对象,然后计算开始和结束索引,最后在指定范围内填充值。
通过这个示例,可以更深入地理解 fill
方法的内部工作机制,并了解如何在实际开发中自定义数组方法。