跳到主要内容

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;在严格模式下,如果未提供第二个参数,thisundefined,与严格模式的规定保持一致。

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

相比之下,forEacheverysomereducemap 方法会自动忽略稀疏数组中的空位。

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]

删除对应项的情况

  1. 使用 splice 删除元素会在数组末尾补上 undefined
  2. 使用 deletepop 删除元素后,数组中的对应位置会被填充 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 方法的工作原理,并在实际开发中根据需要自定义数组方法。

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]

fill 方法示意图

在这个实现中,我扩展了 Array.prototype 添加了一个 myFill 方法。该方法首先验证 this 是否为有效的数组对象,然后计算开始和结束索引,最后在指定范围内填充值。

通过这个示例,可以更深入地理解 fill 方法的内部工作机制,并了解如何在实际开发中自定义数组方法。