实现数组方法 map、filter、reduce、find、some、every
手写 JavaScript 数组常用方法的实现
问题
从零实现数组的 map、filter、reduce、find、some、every 方法。
解答
实现 map
Array.prototype.myMap = function(callback, thisArg) {
// 边界检查
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
const result = [];
for (let i = 0; i < this.length; i++) {
// 跳过稀疏数组的空位
if (i in this) {
// callback 接收三个参数:当前元素、索引、原数组
result.push(callback.call(thisArg, this[i], i, this));
}
}
return result;
};
// 测试
const arr = [1, 2, 3];
console.log(arr.myMap(x => x * 2)); // [2, 4, 6]
实现 filter
Array.prototype.myFilter = function(callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
const result = [];
for (let i = 0; i < this.length; i++) {
if (i in this) {
// 只有 callback 返回 true 时才加入结果
if (callback.call(thisArg, this[i], i, this)) {
result.push(this[i]);
}
}
}
return result;
};
// 测试
const arr = [1, 2, 3, 4, 5];
console.log(arr.myFilter(x => x > 2)); // [3, 4, 5]
实现 reduce
Array.prototype.myReduce = function(callback, initialValue) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
const len = this.length;
let accumulator;
let startIndex = 0;
// 处理初始值
if (arguments.length >= 2) {
accumulator = initialValue;
} else {
// 没有初始值时,找到第一个有效元素作为初始值
if (len === 0) {
throw new TypeError('Reduce of empty array with no initial value');
}
// 跳过稀疏数组的空位
while (startIndex < len && !(startIndex in this)) {
startIndex++;
}
if (startIndex >= len) {
throw new TypeError('Reduce of empty array with no initial value');
}
accumulator = this[startIndex++];
}
for (let i = startIndex; i < len; i++) {
if (i in this) {
// callback 接收四个参数:累加器、当前值、索引、原数组
accumulator = callback(accumulator, this[i], i, this);
}
}
return accumulator;
};
// 测试
const arr = [1, 2, 3, 4];
console.log(arr.myReduce((acc, cur) => acc + cur, 0)); // 10
console.log(arr.myReduce((acc, cur) => acc + cur)); // 10
实现 find
Array.prototype.myFind = function(callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
for (let i = 0; i < this.length; i++) {
if (i in this) {
// 找到第一个满足条件的元素就返回
if (callback.call(thisArg, this[i], i, this)) {
return this[i];
}
}
}
// 没找到返回 undefined
return undefined;
};
// 测试
const arr = [1, 2, 3, 4];
console.log(arr.myFind(x => x > 2)); // 3
console.log(arr.myFind(x => x > 10)); // undefined
实现 some
Array.prototype.mySome = function(callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
for (let i = 0; i < this.length; i++) {
if (i in this) {
// 只要有一个满足条件就返回 true
if (callback.call(thisArg, this[i], i, this)) {
return true;
}
}
}
// 空数组返回 false
return false;
};
// 测试
const arr = [1, 2, 3, 4];
console.log(arr.mySome(x => x > 3)); // true
console.log(arr.mySome(x => x > 10)); // false
console.log([].mySome(x => x > 0)); // false
实现 every
Array.prototype.myEvery = function(callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
for (let i = 0; i < this.length; i++) {
if (i in this) {
// 只要有一个不满足条件就返回 false
if (!callback.call(thisArg, this[i], i, this)) {
return false;
}
}
}
// 空数组返回 true
return true;
};
// 测试
const arr = [1, 2, 3, 4];
console.log(arr.myEvery(x => x > 0)); // true
console.log(arr.myEvery(x => x > 2)); // false
console.log([].myEvery(x => x > 0)); // true
关键点
- 使用
i in this判断稀疏数组的空位,避免处理不存在的元素 - callback 通过
call绑定thisArg,支持指定执行上下文 reduce无初始值时,用第一个有效元素作为初始值,空数组要抛错some空数组返回false,every空数组返回true(逻辑学约定)- 所有方法都要做类型检查,callback 不是函数时抛出 TypeError
目录