手写实现 Array.prototype.every 方法

实现数组的 every 方法,用于检测数组所有元素是否都满足指定条件

问题

Array.prototype.every() 方法用于测试数组中的所有元素是否都能通过指定函数的测试。它返回一个布尔值,只有当数组中的每个元素都满足条件时才返回 true,否则返回 false

需要实现一个自定义的 every 方法,模拟原生 every 方法的行为。

解答

/**
 * 实现 Array.prototype.every 方法
 * @param {Function} callback - 测试函数,接收三个参数:当前元素、索引、原数组
 * @param {*} thisArg - 执行 callback 时使用的 this 值
 * @returns {Boolean} - 所有元素都通过测试返回 true,否则返回 false
 */
Array.prototype.myEvery = function(callback, thisArg) {
  // 边界条件判断
  if (this == null) {
    throw new TypeError('Array.prototype.myEvery called on null or undefined');
  }
  
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }
  
  // 将调用对象转换为对象
  const O = Object(this);
  // 获取数组长度
  const len = O.length >>> 0;
  
  // 遍历数组
  for (let i = 0; i < len; i++) {
    // 只检查数组中实际存在的元素(跳过空位)
    if (i in O) {
      // 调用回调函数,如果返回 false,立即返回 false
      if (!callback.call(thisArg, O[i], i, O)) {
        return false;
      }
    }
  }
  
  // 所有元素都通过测试,返回 true
  return true;
};

使用示例

// 示例1:检查所有元素是否都大于 0
const arr1 = [1, 2, 3, 4, 5];
console.log(arr1.myEvery(item => item > 0)); // true
console.log(arr1.myEvery(item => item > 3)); // false

// 示例2:检查所有元素是否都是偶数
const arr2 = [2, 4, 6, 8];
console.log(arr2.myEvery(num => num % 2 === 0)); // true

// 示例3:使用索引参数
const arr3 = [10, 20, 30, 40];
console.log(arr3.myEvery((item, index) => item === (index + 1) * 10)); // true

// 示例4:使用 thisArg 参数
const threshold = {
  min: 5,
  max: 50
};
const arr4 = [10, 20, 30];
console.log(arr4.myEvery(function(item) {
  return item >= this.min && item <= this.max;
}, threshold)); // true

// 示例5:空数组返回 true(符合原生行为)
const arr5 = [];
console.log(arr5.myEvery(item => item > 100)); // true

// 示例6:稀疏数组(跳过空位)
const arr6 = [1, , 3, , 5];
console.log(arr6.myEvery(item => item > 0)); // true

关键点

  • 类型检查:需要检查 this 是否为 null/undefined,以及 callback 是否为函数
  • 长度处理:使用 >>> 0 确保长度为非负整数
  • 短路逻辑:一旦发现不满足条件的元素,立即返回 false,无需继续遍历
  • 稀疏数组处理:使用 in 操作符检查属性是否存在,跳过数组空位
  • this 绑定:使用 call 方法正确绑定 thisArg 到回调函数
  • 空数组特性:空数组调用 every 返回 true(逻辑学中的”空真”原则)
  • 不修改原数组every 方法不会改变原数组的内容
  • 返回布尔值:使用 ! 运算符将回调函数的返回值转换为布尔值进行判断