文章目录
-
- [一、every 方法核心概念](#一、every 方法核心概念)
-
- [1.1 定义与本质](#1.1 定义与本质)
- [1.2 核心特性](#1.2 核心特性)
- [1.3 与 "部分验证" 的本质区别](#1.3 与 “部分验证” 的本质区别)
- [二、every 方法语法与参数解析](#二、every 方法语法与参数解析)
-
- [2.1 基本语法](#2.1 基本语法)
- [2.2 参数详解](#2.2 参数详解)
-
- [2.2.1 回调函数(callback)](#2.2.1 回调函数(callback))
- [2.2.2 thisArg(可选)](#2.2.2 thisArg(可选))
- [2.3 返回值说明](#2.3 返回值说明)
- [2.4 兼容性说明](#2.4 兼容性说明)
- [三、every 方法基础用法全解析](#三、every 方法基础用法全解析)
-
- [3.1 原始类型数组的验证场景](#3.1 原始类型数组的验证场景)
-
- [3.1.1 数值数组的全域验证](#3.1.1 数值数组的全域验证)
- [3.1.2 字符串数组的规则校验](#3.1.2 字符串数组的规则校验)
- [3.1.3 布尔值数组的状态判断](#3.1.3 布尔值数组的状态判断)
- [3.2 对象数组的多属性验证](#3.2 对象数组的多属性验证)
-
- [3.2.1 单属性统一校验](#3.2.1 单属性统一校验)
- [3.2.2 多属性组合验证](#3.2.2 多属性组合验证)
- [3.3 特殊数组的处理逻辑](#3.3 特殊数组的处理逻辑)
-
- [3.3.1 空数组的业务适配](#3.3.1 空数组的业务适配)
- [3.3.2 稀疏数组的遍历特性](#3.3.2 稀疏数组的遍历特性)
- [3.4 类型判断的全域验证](#3.4 类型判断的全域验证)
-
- [3.4.1 数组元素类型统一校验](#3.4.1 数组元素类型统一校验)
- [3.4.2 多维数组的类型验证](#3.4.2 多维数组的类型验证)
- [四、every 方法高级用法与场景拓展](#四、every 方法高级用法与场景拓展)
-
- [4.1 链式调用与组合验证](#4.1 链式调用与组合验证)
-
- [4.1.1 与 filter 结合的精准验证](#4.1.1 与 filter 结合的精准验证)
- [4.1.2 与 map 结合的转换后验证](#4.1.2 与 map 结合的转换后验证)
- [4.2 类数组对象的全域验证](#4.2 类数组对象的全域验证)
-
- [4.2.1 arguments 对象的参数验证](#4.2.1 arguments 对象的参数验证)
- [4.2.2 DOM 元素集合的状态验证](#4.2.2 DOM 元素集合的状态验证)
- [4.3 嵌套数组的深度全域验证](#4.3 嵌套数组的深度全域验证)
- [4.4 异步场景下的全域验证](#4.4 异步场景下的全域验证)
-
- [4.4.1 异步接口的全量验证](#4.4.1 异步接口的全量验证)
- [4.4.2 异步表单的全量验证](#4.4.2 异步表单的全量验证)
- [五、every 方法实战案例精讲](#五、every 方法实战案例精讲)
-
- [5.1 表单验证实战](#5.1 表单验证实战)
-
- [5.1.1 全量必填项验证](#5.1.1 全量必填项验证)
- [5.1.2 字段格式全量校验](#5.1.2 字段格式全量校验)
- [5.2 DOM 操作实战](#5.2 DOM 操作实战)
-
- [5.2.1 复选框全选状态验证](#5.2.1 复选框全选状态验证)
- [5.2.2 元素样式统一验证](#5.2.2 元素样式统一验证)
- [5.3 数据处理实战](#5.3 数据处理实战)
-
- [5.3.1 数据完整性校验](#5.3.1 数据完整性校验)
- [5.3.2 权限全量验证](#5.3.2 权限全量验证)
- [5.4 接口交互实战](#5.4 接口交互实战)
-
- [5.4.1 批量请求结果验证](#5.4.1 批量请求结果验证)
- [5.4.2 请求参数全量校验](#5.4.2 请求参数全量校验)
- [六、every 与其他数组方法的区别对比](#六、every 与其他数组方法的区别对比)
-
- [6.1 every vs some](#6.1 every vs some)
- [6.2 every vs filter](#6.2 every vs filter)
- [6.3 every vs every(手动实现)](#6.3 every vs every(手动实现))
- [6.4 every vs forEach](#6.4 every vs forEach)
- [七、every 方法常见问题与避坑指南](#七、every 方法常见问题与避坑指南)
-
- [7.1 空数组返回 true 的逻辑陷阱](#7.1 空数组返回 true 的逻辑陷阱)
- [7.2 回调函数未返回布尔值](#7.2 回调函数未返回布尔值)
- [7.3 this 指向丢失问题](#7.3 this 指向丢失问题)
- [7.4 稀疏数组的遍历遗漏](#7.4 稀疏数组的遍历遗漏)
- [7.5 异步回调的同步执行问题](#7.5 异步回调的同步执行问题)
- [7.6 类型隐式转换导致误判](#7.6 类型隐式转换导致误判)
- [八、every 方法性能优化与兼容性处理](#八、every 方法性能优化与兼容性处理)
-
- [8.1 性能优化技巧](#8.1 性能优化技巧)
-
- [8.1.1 利用短路特性优化判断顺序](#8.1.1 利用短路特性优化判断顺序)
- [8.1.2 大型数组的分片异步处理](#8.1.2 大型数组的分片异步处理)
- [8.1.3 避免回调中的重型操作](#8.1.3 避免回调中的重型操作)
- [8.2 兼容性处理方案](#8.2 兼容性处理方案)
-
- [8.2.1 低版本浏览器 Polyfill](#8.2.1 低版本浏览器 Polyfill)
- [8.2.2 类数组对象的兼容性处理](#8.2.2 类数组对象的兼容性处理)
- [8.3 TypeScript 中的类型安全使用](#8.3 TypeScript 中的类型安全使用)
- [8.4 前端框架中的使用注意事项](#8.4 前端框架中的使用注意事项)
-
- [8.4.1 React 中的性能优化](#8.4.1 React 中的性能优化)
- [8.4.2 Vue 中的响应式处理](#8.4.2 Vue 中的响应式处理)
一、every 方法核心概念
1.1 定义与本质
JavaScript 的every()
方法是数组原型上的迭代验证方法,用于检测数组中所有元素是否均满足指定条件。其本质是通过遍历数组执行回调函数,对元素进行全量校验,属于 "全域性验证" 工具,核心价值在于快速判断数组是否符合统一规则。
1.2 核心特性
-
短路执行 :一旦发现不满足条件的元素,立即停止遍历并返回
false
,剩余元素不再处理 -
布尔值返回 :仅返回
true
(所有元素满足条件)或false
(存在不满足元素),不返回具体元素 -
无副作用:遍历过程中不会修改原始数组的元素或结构
-
稀疏数组处理:会跳过数组中的空槽(empty),仅对已初始化的元素执行回调
1.3 与 "部分验证" 的本质区别
every()
与some()
方法形成逻辑互补:
-
every()
:追求 "全部符合",体现逻辑与(AND)关系 -
some()
:追求 "存在符合",体现逻辑或(OR)关系
当需求是 "验证数组整体合规性" 时(如所有表单字段均有效、所有数据均已加载),every()
是最优选择,相比for
循环能减少无效遍历。
二、every 方法语法与参数解析
2.1 基本语法
javascript
array.every(callback(element[, index[, array]])[, thisArg])
2.2 参数详解
2.2.1 回调函数(callback)
必传参数,用于定义元素的验证规则,必须返回布尔值(true
/false
)。包含三个参数:
-
element:当前正在处理的数组元素(必选)
-
index:当前元素的索引值(可选)
-
array :调用
every()
方法的原数组(可选)
代码示例:参数完整使用
javascript
const scores = [85, 92, 78, 95];
// 验证所有分数是否大于70且索引为偶数的元素大于80
const allQualified = scores.every((element, index, array) => {
console.log(`元素:${element},索引:${index},数组长度:${array.length}`);
const baseRule = element > 70;
const indexRule = index % 2 === 0? element > 80 : true;
return baseRule && indexRule;
});
console.log(allQualified); // false(索引2的元素78不满足indexRule)
2.2.2 thisArg(可选)
指定回调函数中this
关键字的指向。未传入时:
-
非严格模式下,
this
指向全局对象(浏览器为window
,Node.js 为global
) -
严格模式下,
this
为undefined
代码示例:thisArg 实际应用
javascript
const validator = {
minAge: 18,
maxAge: 60,
checkAgeRange: function(age) {
return age >= this.minAge && age <= this.maxAge;
}
};
const teamMembers = [
{ name: "张三", age: 22 },
{ name: "李四", age: 35 },
{ name: "王五", age: 28 }
];
// 传入thisArg绑定validator对象
const allInAgeRange = teamMembers.every(validator.checkAgeRange, validator);
console.log(allInAgeRange); // true
2.3 返回值说明
-
数组中所有元素 使回调返回
true
→ 返回true
-
数组中存在至少一个元素 使回调返回
false
→ 返回false
-
若数组为空,无论条件如何,始终返回
true
(逻辑上 "空集合的所有元素均满足条件")
代码示例:空数组特殊情况
javascript
const emptyArr = [];
// 空数组返回true,与some()的false形成对比
const result1 = emptyArr.every(item => item > 0);
const result2 = emptyArr.every(item => false);
console.log(result1, result2); // true true
2.4 兼容性说明
-
支持环境:ES5 及以上浏览器(IE9+)、Node.js 0.10+
-
低版本兼容:IE8 及以下需通过 polyfill 实现(见第八章)
三、every 方法基础用法全解析
3.1 原始类型数组的验证场景
3.1.1 数值数组的全域验证
场景:判断考试成绩是否全部及格(≥60 分)
javascript
const examScores = [75, 82, 66, 91, 60];
// 验证所有分数是否≥60
const allPassed = examScores.every(score => score >= 60);
console.log(allPassed); // true
const scoresWithFail = [75, 58, 88, 90];
const hasFail = scoresWithFail.every(score => score >= 60);
console.log(hasFail); // false(58分不及格)
3.1.2 字符串数组的规则校验
场景:判断所有用户名是否均符合 "3-10 位字母数字组合" 规则
javascript
const usernames = ["zhangsan123", "lisi45", "wangwu678"];
// 正则验证:3-10位字母数字
const usernameRule = /^[a-zA-Z0-9]{3,10}$/;
const allValidUsernames = usernames.every(name => usernameRule.test(name));
console.log(allValidUsernames); // true
const invalidUsernames = ["zh", "zhao@123", "qian1234567890"];
const hasInvalidName = invalidUsernames.every(name => usernameRule.test(name));
console.log(hasInvalidName); // false
3.1.3 布尔值数组的状态判断
场景:判断所有任务是否均已完成(isCompleted 为 true)
javascript
const tasks = [
{ id: 1, title: "需求分析", isCompleted: true },
{ id: 2, title: "接口开发", isCompleted: true },
{ id: 3, title: "测试验收", isCompleted: true }
];
const allTasksDone = tasks.every(task => task.isCompleted);
console.log(allTasksDone); // true
tasks[2].isCompleted = false;
console.log(tasks.every(task => task.isCompleted)); // false
3.2 对象数组的多属性验证
3.2.1 单属性统一校验
场景:判断所有商品是否均有库存(stock > 0)
javascript
const products = [
{ id: 1, name: "笔记本", stock: 25 },
{ id: 2, name: "耳机", stock: 18 },
{ id: 3, name: "鼠标", stock: 40 }
];
// 验证所有商品库存>0
const allInStock = products.every(product => product.stock > 0);
console.log(allInStock); // true
3.2.2 多属性组合验证
场景:判断所有订单是否均为 "已支付且金额≥10 元"
javascript
const orders = [
{ id: 101, amount: 299, paid: true },
{ id: 102, amount: 15, paid: true },
{ id: 103, amount: 89, paid: true }
];
// 多条件组合验证
const allValidOrders = orders.every(order =>
order.paid && order.amount >= 10
);
console.log(allValidOrders); // true
orders[1].amount = 5;
console.log(orders.every(order => order.paid && order.amount >= 10)); // false
3.3 特殊数组的处理逻辑
3.3.1 空数组的业务适配
场景:处理空数组时避免逻辑异常
javascript
function checkAllPositive(arr) {
// 空数组单独处理,返回业务默认值
if (arr.length === 0) {
console.warn("数组为空,返回默认值false");
return false;
}
return arr.every(item => item > 0);
}
console.log(checkAllPositive([])); // false(业务默认值)
console.log(checkAllPositive([1, 3, 5])); // true
3.3.2 稀疏数组的遍历特性
场景:理解稀疏数组中空槽的处理逻辑
javascript
// 创建稀疏数组(索引1和3为空)
const sparseScores = [80, , 90, , 85];
let checkCount = 0;
const allAbove70 = sparseScores.every(score => {
checkCount++;
return score > 70;
});
console.log(allAbove70); // true
console.log(checkCount); // 3(仅处理索引0、2、4的元素)
3.4 类型判断的全域验证
3.4.1 数组元素类型统一校验
场景:判断数组中所有元素是否均为数字类型
javascript
const numberArray = [123, 45.67, 890];
const mixedArray = [123, "456", true];
// 验证所有元素是否为数字(排除NaN)
const allNumbers = numberArray.every(item =>
typeof item === "number" &&!isNaN(item)
);
console.log(allNumbers); // true
const hasNonNumber = mixedArray.every(item =>
typeof item === "number" &&!isNaN(item)
);
console.log(hasNonNumber); // false
3.4.2 多维数组的类型验证
场景:判断多维数组中所有子数组是否均为长度 2 的坐标数据
javascript
const coordinates = [[10, 20], [30, 40], [50, 60]];
const invalidCoordinates = [[10, 20], [30], [50, 60, 70]];
// 验证所有子数组长度是否为2
const allValidCoords = coordinates.every(coord =>
Array.isArray(coord) && coord.length === 2
);
console.log(allValidCoords); // true
console.log(invalidCoordinates.every(coord =>
Array.isArray(coord) && coord.length === 2
)); // false
四、every 方法高级用法与场景拓展
4.1 链式调用与组合验证
4.1.1 与 filter 结合的精准验证
场景:先筛选特定数据,再验证全域合规性
javascript
const productList = [
{ name: "手机", category: "数码", price: 3999, stock: 15 },
{ name: "耳机", category: "数码", price: 799, stock: 30 },
{ name: "冰箱", category: "家电", price: 2999, stock: 8 },
{ name: "键盘", category: "数码", price: 299, stock: 22 }
];
// 先筛选数码类商品,再验证是否均满足价格<4000且有库存
const allDigitalValid = productList
.filter(product => product.category === "数码")
.every(product => product.price < 4000 && product.stock > 0);
console.log(allDigitalValid); // true
4.1.2 与 map 结合的转换后验证
场景:先转换数据格式,再执行全域验证
javascript
const orderData = [
{ id: 1, quantity: 2, unitPrice: 150 },
{ id: 2, quantity: 3, unitPrice: 80 },
{ id: 3, quantity: 1, unitPrice: 200 }
];
// 先计算订单总价,再验证所有订单总价是否≥100
const allOrdersQualified = orderData
.map(order => order.quantity * order.unitPrice)
.every(total => total >= 100);
console.log(allOrdersQualified); // true(2*150=300、3*80=240、1*200=200)
4.2 类数组对象的全域验证
every()
可通过call()
/apply()
方法应用于类数组对象,如arguments
、NodeList
、HTMLCollection
等。
4.2.1 arguments 对象的参数验证
场景:验证函数所有参数是否均为正整数
javascript
function calculateTotal() {
// 验证所有参数是否为正整数
const allPositiveInt = Array.prototype.every.call(arguments, arg =>
Number.isInteger(arg) && arg > 0
);
if (!allPositiveInt) {
throw new Error("所有参数必须为正整数");
}
return Array.from(arguments).reduce((sum, curr) => sum + curr, 0);
}
console.log(calculateTotal(10, 20, 30)); // 60
console.log(calculateTotal(10, "20", 30)); // 抛出错误
4.2.2 DOM 元素集合的状态验证
场景:验证页面中所有必填输入框是否均已填写
javascript
// 获取所有必填输入框(class含required)
const requiredInputs = document.querySelectorAll("input.required");
// 验证所有必填输入框是否均有值
const allFilled = Array.prototype.every.call(requiredInputs, input =>
input.value.trim()!== ""
);
if (allFilled) {
console.log("所有必填项已填写");
} else {
console.log("存在未填写的必填项");
}
4.3 嵌套数组的深度全域验证
场景:验证多维数组中所有元素是否均满足指定条件
javascript
const nestedData = [
[10, 20, 30],
[40, [50, 60], 70],
[80, 90, [100, 110]]
];
// 递归验证所有嵌套元素是否均为正数
function allPositiveInNested(arr) {
return arr.every(item => {
return Array.isArray(item)
? allPositiveInNested(item)
: typeof item === "number" && item > 0;
});
}
console.log(allPositiveInNested(nestedData)); // true
// 插入负数后验证
nestedData[1][1][1] = -60;
console.log(allPositiveInNested(nestedData)); // false
4.4 异步场景下的全域验证
every()
本身不支持异步回调,但可通过Promise
封装实现异步全域验证,需等待所有异步操作完成或遇到第一个失败立即终止。
4.4.1 异步接口的全量验证
场景:验证多个接口请求是否均返回成功
javascript
// 模拟异步接口请求
function fetchResource(url) {
return new Promise((resolve) => {
setTimeout(() => {
// 模拟url3请求失败
if (url === "url3") {
resolve({ success: false, message: "资源不存在" });
} else {
resolve({ success: true, data: {} });
}
}, 800);
});
}
// 异步every实现:遇到失败立即返回false
async function asyncEvery(arr, asyncCallback) {
for (const item of arr) {
const result = await asyncCallback(item);
if (!result) return false; // 有一个失败则终止
}
return true;
}
// 验证所有接口是否均成功
const resourceUrls = ["url1", "url2", "url3"];
const allRequestsSuccess = await asyncEvery(resourceUrls, async (url) => {
const response = await fetchResource(url);
return response.success;
});
console.log(allRequestsSuccess); // false
4.4.2 异步表单的全量验证
场景:验证表单所有字段的异步规则是否均通过
javascript
// 模拟字段异步验证(如用户名唯一性校验)
const validateFieldAsync = async (field) => {
switch (field.name) {
case "username":
// 模拟用户名查重接口
return new Promise(resolve => {
setTimeout(() => {
resolve(field.value!== "admin"); // admin已被占用
}, 600);
});
case "email":
// 邮箱格式同步验证
return /^[^s@]+@[^s@]+.[^s@]+$/.test(field.value);
default:
return field.value.trim()!== "";
}
};
// 表单字段
const formFields = [
{ name: "username", value: "zhangsan" },
{ name: "email", value: "zhangsan@example.com" },
{ name: "password", value: "123456" }
];
// 验证所有字段是否均通过异步验证
const allFieldsValid = await asyncEvery(formFields, validateFieldAsync);
console.log(allFieldsValid); // true
五、every 方法实战案例精讲
5.1 表单验证实战
5.1.1 全量必填项验证
场景:表单提交前验证所有必填字段是否均已填写
javascript
// 表单数据
const formData = {
username: "lisi",
password: "",
email: "lisi@example.com",
phone: "13800138000",
address: ""
};
// 必填字段配置
const requiredFields = [
{ key: "username", label: "用户名" },
{ key: "password", label: "密码" },
{ key: "phone", label: "手机号" }
];
// 验证所有必填项是否已填写
const allRequiredFilled = requiredFields.every(field => {
const value = formData[field.key];
const isFilled = value!== undefined && value!== null && value.trim()!== "";
if (!isFilled) {
console.error(`必填项【${field.label}】未填写`);
}
return isFilled;
});
if (allRequiredFilled) {
console.log("表单验证通过,可提交");
} else {
console.error("存在未填写的必填项");
}
// 输出:必填项【密码】未填写 → 存在未填写的必填项
5.1.2 字段格式全量校验
场景:验证所有表单字段是否均符合格式规则
javascript
// 表单数据
const userForm = {
username: "wangwu123",
email: "wangwu.example.com", // 格式错误
phone: "13800138000",
age: 25
};
// 验证规则配置
const validationRules = [
{
key: "username",
validator: val => /^[a-zA-Z0-9]{3,15}$/.test(val),
message: "用户名需为3-15位字母数字组合"
},
{
key: "email",
validator: val => /^[^s@]+@[^s@]+.[^s@]+$/.test(val),
message: "邮箱格式不正确"
},
{
key: "phone",
validator: val => /^1[3-9]d{9}$/.test(val),
message: "手机号格式不正确"
},
{
key: "age",
validator: val => val >= 18 && val <= 60,
message: "年龄需在18-60之间"
}
];
// 验证所有字段是否符合规则
const allFieldsValid = validationRules.every(rule => {
const value = userForm[rule.key];
const isValid = rule.validator(value);
if (!isValid) {
console.error(`【${rule.key}】${rule.message}`);
}
return isValid;
});
console.log("字段格式验证结果:", allFieldsValid); // false
5.2 DOM 操作实战
5.2.1 复选框全选状态验证
场景:验证列表中所有复选框是否均已勾选
javascript
// HTML结构示例
// <div class="item"><input type="checkbox" checked> 选项1</div>
// <div class="item"><input type="checkbox"> 选项2</div>
// <div class="item"><input type="checkbox" checked> 选项3</div>
// 获取所有复选框
const checkboxes = document.querySelectorAll(".item input[type='checkbox']");
// 验证是否全选
const isAllChecked = Array.prototype.every.call(checkboxes, checkbox => {
return checkbox.checked;
});
console.log("是否全选:", isAllChecked); // false(选项2未勾选)
// 全选按钮点击事件
document.getElementById("selectAll").addEventListener("click", () => {
Array.prototype.forEach.call(checkboxes, checkbox => {
checkbox.checked = true;
});
console.log("是否全选:", Array.prototype.every.call(checkboxes, c => c.checked)); // true
});
5.2.2 元素样式统一验证
场景:验证所有列表项是否均符合指定样式规则
javascript
// 获取所有列表项
const listItems = document.querySelectorAll(".product-item");
const maxAllowedWidth = 300; // 最大允许宽度300px
const requiredBorder = "1px solid #e5e7eb"; // 要求边框样式
// 验证所有列表项样式是否合规
const allStylesValid = Array.prototype.every.call(listItems, item => {
const computedStyle = window.getComputedStyle(item);
const widthValid = parseInt(computedStyle.width) <= maxAllowedWidth;
const borderValid = computedStyle.border === requiredBorder;
if (!widthValid) {
console.error(`元素${item.dataset.id}宽度超限`);
}
if (!borderValid) {
console.error(`元素${item.dataset.id}边框样式不符`);
}
return widthValid && borderValid;
});
console.log("列表项样式验证结果:", allStylesValid);
5.3 数据处理实战
5.3.1 数据完整性校验
场景:验证接口返回的列表数据是否均包含必填属性
javascript
// 接口返回的用户数据
const userList = [
{ id: 1, name: "张三", age: 22, avatar: "url1" },
{ id: 2, name: "李四", avatar: "url2" }, // 缺少age属性
{ id: 3, name: "王五", age: 28, avatar: "url3" }
];
// 数据必填属性
const requiredProps = ["id", "name", "age", "avatar"];
// 验证所有用户数据是否均包含必填属性
const allDataComplete = userList.every(user => {
return requiredProps.every(prop => {
const hasProp = prop in user;
if (!hasProp) {
console.error(`用户${user.id || '未知'}缺少属性:${prop}`);
}
return hasProp;
});
});
console.log("数据完整性验证结果:", allDataComplete); // false
5.3.2 权限全量验证
场景:验证当前用户是否拥有所有指定操作的权限
javascript
// 当前用户权限列表
const userPermissions = [
"user:view", "user:edit", "user:delete",
"order:view", "order:edit"
];
// 某个操作所需的全部权限
const requiredPermissions = ["user:view", "user:edit", "order:delete"];
// 验证用户是否拥有所有所需权限
function hasAllPermissions(userPerms, requiredPerms) {
return requiredPerms.every(perm => userPerms.includes(perm));
}
const hasPermission = hasAllPermissions(userPermissions, requiredPermissions);
console.log("是否拥有全部操作权限:", hasPermission); // false(缺少order:delete)
// 权限不足时的处理
if (!hasPermission) {
const missingPerms = requiredPermissions.filter(perm =>!userPermissions.includes(perm));
console.log("缺少权限:", missingPerms); // 缺少权限:["order:delete"]
}
5.4 接口交互实战
5.4.1 批量请求结果验证
场景:验证批量删除接口的返回结果是否均成功
javascript
// 模拟批量删除接口请求
function deleteItem(id) {
return new Promise((resolve) => {
setTimeout(() => {
// 模拟id=2的删除失败
if (id === 2) {
resolve({ code: 500, message: "删除失败", id });
} else {
resolve({ code: 200, message: "删除成功", id });
}
}, 500);
});
}
// 待删除的项ID
const deleteIds = [1, 2, 3];
// 执行批量删除并验证结果
async function batchDeleteAndVerify(ids) {
// 发起所有删除请求
const deletePromises = ids.map(id => deleteItem(id));
const results = await Promise.all(deletePromises);
// 验证所有删除是否均成功
const allDeleted = results.every(result => result.code === 200);
if (allDeleted) {
console.log("所有项均删除成功");
} else {
const failedIds = results.filter(r => r.code!== 200).map(r => r.id);
console.log(`删除失败的项ID:${failedIds.join(",")}`);
}
return allDeleted;
}
batchDeleteAndVerify(deleteIds); // 删除失败的项ID:2
5.4.2 请求参数全量校验
场景:验证接口请求参数是否均符合规则
javascript
// 接口请求参数
const requestParams = {
page: 1,
size: 30, // 超出最大限制
sort: "createTime",
startTime: "2024-01-01",
endTime: "2024-01-31"
};
// 参数验证规则
const paramValidationRules = [
{
key: "page",
validator: val => val >= 1 && val <= 100,
message: "页码需在1-100之间"
},
{
key: "size",
validator: val => val >= 10 && val <= 20,
message: "每页条数需在10-20之间"
},
{
key: "sort",
validator: val => ["createTime", "updateTime", "name"].includes(val),
message: "排序字段不合法"
},
{
key: "endTime",
validator: val => {
const start = new Date(requestParams.startTime);
const end = new Date(val);
return end >= start;
},
message: "结束时间不能早于开始时间"
}
];
// 验证所有参数是否符合规则
const allParamsValid = paramValidationRules.every(rule => {
const value = requestParams[rule.key];
const isValid = rule.validator(value);
if (!isValid) {
console.error(`参数${rule.key}:${rule.message}`);
}
return isValid;
});
if (allParamsValid) {
console.log("参数验证通过,发起请求");
} else {
console.error("参数验证失败");
}
// 输出:参数size:每页条数需在10-20之间 → 参数验证失败
六、every 与其他数组方法的区别对比
6.1 every vs some
两者均为逻辑验证方法,核心区别在于验证逻辑的相反性:
特性 | every() | some() |
---|---|---|
逻辑关系 | 逻辑与(AND) | 逻辑或(OR) |
短路时机 | 遇到 false 立即停止 | 遇到 true 立即停止 |
空数组返回值 | true | false |
核心场景 | 全量合规性验证 | 存在性检测 |
代码对比示例:
javascript
const numbers = [2, 4, 6, 7, 8];
// every:是否全为偶数(有奇数→false)
const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // false
// some:是否存在奇数(有奇数→true)
const hasOdd = numbers.some(num => num % 2!== 0);
console.log(hasOdd); // true
使用场景区分:
-
验证 "所有元素必须符合" 用
every()
(如所有表单字段均有效) -
验证 "存在元素符合" 用
some()
(如存在未读消息)
6.2 every vs filter
every()
侧重验证结果,filter()
侧重数据筛选,核心差异在返回值和执行逻辑:
特性 | every() | filter() |
---|---|---|
返回值 | 布尔值(true/false) | 符合条件的元素数组 |
执行逻辑 | 短路执行,不全量遍历 | 全量遍历,返回所有符合元素 |
核心用途 | 条件验证 | 数据筛选 |
性能 | 大数据量下可能更优(短路特性) | 始终遍历全量元素 |
代码对比示例:
javascript
const products = [
{ name: "手机", price: 3999, stock: 15 },
{ name: "耳机", price: 799, stock: 0 },
{ name: "键盘", price: 299, stock: 22 }
];
// every:验证所有商品是否有库存(短路,遇到stock=0立即返回false)
console.time("every");
const allInStock = products.every(p => p.stock > 0);
console.timeEnd("every"); // 约0.05ms
console.log(allInStock); // false
// filter:筛选有库存的商品(遍历所有元素)
console.time("filter");
const inStockProducts = products.filter(p => p.stock > 0);
console.timeEnd("filter"); // 约0.1ms
console.log(inStockProducts.length > 0); // true
使用场景区分:
-
仅需判断 "是否全符合" 无需元素 → 用
every()
-
需要获取 "所有符合条件的元素" → 用
filter()
6.3 every vs every(手动实现)
原生every()
与手动 for 循环实现的对比:
特性 | 原生 every () | 手动 for 循环 |
---|---|---|
代码简洁性 | 高,一行代码即可 | 低,需编写循环结构 |
短路特性 | 原生支持,自动停止 | 需手动添加 break 逻辑 |
稀疏数组处理 | 自动跳过空槽 | 需手动判断元素是否存在 |
可读性 | 高,语义明确 | 低,需理解循环逻辑 |
代码对比示例:
javascript
const scores = [85, 92, 78, 60];
// 原生every()
const nativeResult = scores.every(score => score >= 60);
// 手动for循环实现
function manualEvery(arr, callback) {
for (let i = 0; i < arr.length; i++) {
// 跳过稀疏数组的空槽
if (!(i in arr)) continue;
if (!callback(arr[i], i, arr)) {
return false; // 短路:遇到false立即返回
}
}
return true;
}
const manualResult = manualEvery(scores, score => score >= 60);
console.log(nativeResult, manualResult); // true true
使用场景区分:
-
日常开发优先使用原生
every()
(简洁高效) -
特殊场景(如自定义空槽处理逻辑)可手动实现
6.4 every vs forEach
forEach()
是遍历工具,every()
是验证工具,核心差异在功能定位:
特性 | every() | forEach() |
---|---|---|
功能定位 | 条件验证工具 | 遍历执行工具 |
返回值 | 布尔值 | undefined |
短路执行 | 支持(返回 false 终止) | 不支持(必须遍历所有元素) |
核心用途 | 判断数组是否全符合条件 | 对每个元素执行副作用操作 |
代码对比示例:
javascript
const users = [
{ name: "张三", age: 17 },
{ name: "李四", age: 20 },
{ name: "王五", age: 16 }
];
// every:验证所有用户是否成年(短路,遇到17岁立即返回false)
let everyCount = 0;
const allAdult = users.every(user => {
everyCount++;
return user.age >= 18;
});
console.log(allAdult, everyCount); // false 1
// forEach:遍历所有用户,无法短路
let forEachCount = 0;
users.forEach(user => {
forEachCount++;
console.log(`${user.name}年龄:${user.age}`);
});
console.log(forEachCount); // 3
使用场景区分:
-
需验证数组全域条件 → 用
every()
-
需对每个元素执行操作(如 DOM 渲染) → 用
forEach()
七、every 方法常见问题与避坑指南
7.1 空数组返回 true 的逻辑陷阱
问题 :空数组调用every()
始终返回true
,易导致业务逻辑异常
javascript
const emptyArr = [];
// 错误认知:空数组会返回false
const allPositive = emptyArr.every(item => item > 0);
console.log(allPositive); // true(与预期不符)
// 业务场景错误示例:判断列表是否全选
function isAllSelected(items) {
// 空列表时返回true,导致认为已全选
return items.every(item => item.selected);
}
console.log(isAllSelected([])); // true(错误结果)
避坑建议:结合数组长度判断,明确业务默认值
javascript
function isAllSelected(items) {
// 空数组返回业务默认值false
if (items.length === 0) return false;
return items.every(item => item.selected);
}
console.log(isAllSelected([])); // false(正确结果)
7.2 回调函数未返回布尔值
问题 :回调函数未显式返回值,默认返回undefined
被当作false
处理
javascript
const numbers = [10, 20, 30, 40];
// 错误:回调无return,默认返回undefined→false
const allGreaterThan5 = numbers.every(num => {
num > 5; // 缺少return关键字
});
console.log(allGreaterThan5); // false(错误结果)
// 正确写法
const allGreaterThan5Correct = numbers.every(num => num > 5);
console.log(allGreaterThan5Correct); // true
避坑建议:
-
确保回调函数始终返回布尔值
-
简单条件直接使用箭头函数隐式返回
-
复杂逻辑显式添加 return 语句
7.3 this 指向丢失问题
问题 :回调函数为普通函数时,this
指向异常导致验证失败
javascript
const priceValidator = {
minPrice: 10,
checkPrice: function(price) {
// this指向window,minPrice为undefined
return price >= this.minPrice;
}
};
const products = [
{ name: "钢笔", price: 15 },
{ name: "笔记本", price: 8 },
{ name: "尺子", price: 12 }
];
// 错误:this指向丢失
const allQualified = products.every(priceValidator.checkPrice);
console.log(allQualified); // false(错误,实际只有笔记本不达标)
避坑建议:三种绑定 this 的方式
javascript
// 方式1:使用bind绑定this
const allQualified1 = products.every(priceValidator.checkPrice.bind(priceValidator));
// 方式2:使用箭头函数
const allQualified2 = products.every(price => priceValidator.checkPrice(price));
// 方式3:传入thisArg参数
const allQualified3 = products.every(priceValidator.checkPrice, priceValidator);
console.log(allQualified1, allQualified2, allQualified3); // false false false(正确结果)
7.4 稀疏数组的遍历遗漏
问题:稀疏数组中的空槽被跳过,导致验证逻辑不完整
javascript
// 稀疏数组(索引1为空)
const sparseScores = [80, , 90, 85];
// 需求:验证所有元素(包括空槽)是否均为数字
const allNumbers = sparseScores.every(score => typeof score === "number");
console.log(allNumbers); // true(错误,索引1为空槽)
// 实际遍历的元素
let checkedElements = [];
sparseScores.every(score => {
checkedElements.push(score);
return typeof score === "number";
});
console.log(checkedElements); // [80, 90, 85](遗漏空槽)
避坑建议:先填充稀疏数组为密集数组
javascript
// 方法1:用map填充空槽为undefined
const denseScores = sparseScores.map(score => score);
// 方法2:用Array.from转换
const denseScores2 = Array.from(sparseScores);
// 验证密集数组
const allNumbersCorrect = denseScores.every(score => typeof score === "number");
console.log(allNumbersCorrect); // false(正确,索引1为undefined)
7.5 异步回调的同步执行问题
问题 :在回调中使用异步操作,every()
无法等待异步结果
javascript
const urls = ["url1", "url2", "url3"];
// 错误:异步操作不会阻塞every执行
const allUrlsValid = urls.every(async (url) => {
const response = await fetch(url);
return response.ok; // 异步结果无法被捕获
});
console.log(allUrlsValid); // Promise { <pending> }(非布尔值)
避坑建议:使用自定义异步 every 实现
javascript
// 正确:异步every封装
async function asyncEvery(arr, asyncCallback) {
for (const item of arr) {
const result = await asyncCallback(item);
if (!result) return false;
}
return true;
}
// 使用异步every
const allUrlsValid = await asyncEvery(urls, async (url) => {
const response = await fetch(url);
return response.ok;
});
console.log(allUrlsValid); // 正确的布尔值
7.6 类型隐式转换导致误判
问题 :使用==
进行比较,类型隐式转换导致验证不准确
javascript
const mixedArray = [0, "0", false, null];
// 错误:0 == false为true,导致误判
const allFalse = mixedArray.every(item => item == false);
console.log(allFalse); // true(错误,"0"和null与false不严格相等)
// 正确:使用===严格比较
const allFalseStrict = mixedArray.every(item => item === false);
console.log(allFalseStrict); // false(正确,仅第3个元素为false)
避坑建议:
-
回调函数中始终使用
===
和!==
进行严格比较 -
对特殊值(如 0、""、null、undefined)单独处理
-
先进行类型判断,再执行值比较
八、every 方法性能优化与兼容性处理
8.1 性能优化技巧
8.1.1 利用短路特性优化判断顺序
every()
遇到false
立即停止,应将 "最可能返回 false" 的条件放在前面,减少无效计算。
优化前:
javascript
const products = [/* 10万条商品数据 */];
// 先执行复杂计算,再判断简单条件
const allQualified = products.every(product => {
const discountPrice = product.price * (1 - product.discount); // 复杂计算
return discountPrice >= 100 && product.stock > 0;
});
优化后:
javascript
const allQualifiedOpt = products.every(product => {
// 先判断简单条件,不满足直接返回false
if (product.stock <= 0) return false;
// 仅满足简单条件时才执行复杂计算
const discountPrice = product.price * (1 - product.discount);
return discountPrice >= 100;
});
8.1.2 大型数组的分片异步处理
对于 10 万条以上的大型数组,同步执行every()
可能阻塞主线程,需分片异步处理。
javascript
async function chunkedEvery(largeArray, condition, chunkSize = 2000) {
const chunks = [];
// 分割数组为分片
for (let i = 0; i < largeArray.length; i += chunkSize) {
chunks.push(largeArray.slice(i, i + chunkSize));
}
// 逐个分片验证,遇到false立即返回
for (const chunk of chunks) {
const result = chunk.every(condition);
if (!result) return false;
// 让出主线程,避免阻塞
await new Promise(resolve => setTimeout(resolve, 0));
}
return true;
}
// 使用示例
const largeArray = Array.from({ length: 100000 }, (_, i) => ({
value: i + 1,
valid: i % 1000!== 0 // 第1000、2000...项无效
}));
const allValid = await chunkedEvery(largeArray, item => item.valid);
console.log(allValid); // false
8.1.3 避免回调中的重型操作
回调函数中应避免 DOM 操作、大量计算等重型操作,可先执行every()
验证,再集中处理操作。
优化前:
javascript
// 回调中包含DOM操作,性能差
const hasInvalidItem = items.every(item => {
const element = document.createElement("div"); // 重型操作
element.textContent = item.name;
document.body.appendChild(element);
return item.isValid;
});
优化后:
javascript
// 先验证,再执行DOM操作
const allValid = items.every(item => item.isValid);
if (allValid) {
// 集中执行DOM操作
items.forEach(item => {
const element = document.createElement("div");
element.textContent = item.name;
document.body.appendChild(element);
});
}
8.2 兼容性处理方案
8.2.1 低版本浏览器 Polyfill
针对 IE8 及以下不支持every()
的浏览器,可添加 Polyfill 实现 ES5 标准的every()
方法。
javascript
if (!Array.prototype.every) {
Array.prototype.every = function(callback, thisArg) {
// 检测回调是否为函数
if (typeof callback!== "function") {
throw new TypeError("Callback must be a function");
}
// 转换为对象,处理原始类型数组
const obj = Object(this);
// 获取数组长度(无符号右移确保为非负整数)
const len = obj.length >>> 0;
for (let i = 0; i < len; i++) {
// 仅处理已初始化的元素(跳过空槽)
if (i in obj) {
const value = obj[i];
// 调用回调,绑定thisArg
if (!callback.call(thisArg, value, i, obj)) {
return false; // 短路:遇到false立即返回
}
}
}
return true; // 所有元素均满足条件
};
}
8.2.2 类数组对象的兼容性处理
部分旧环境中,Array.prototype.call()
可能存在兼容性问题,可先将类数组转换为真正的数组。
javascript
function everyForArrayLike(arrayLike, callback, thisArg) {
// 兼容性转换:类数组→数组
const arr = Array.prototype.slice.call(arrayLike);
// 调用原生every
return arr.every(callback, thisArg);
}
// 使用示例:处理arguments对象
function checkAllPositive() {
return everyForArrayLike(arguments, arg => arg > 0);
}
console.log(checkAllPositive(1, 2, 3)); // true
console.log(checkAllPositive(1, -2, 3)); // false
8.3 TypeScript 中的类型安全使用
在 TypeScript 中使用every()
时,通过泛型指定类型,避免类型错误,提升代码健壮性。
javascript
// 定义接口类型
interface Product {
id: number;
name: string;
price: number;
stock: number;
}
// 类型化数组
const products: Product[] = [
{ id: 1, name: "手机", price: 3999, stock: 15 },
{ id: 2, name: "耳机", price: 799, stock: 30 }
];
// 类型安全的every调用
const allInStock: boolean = products.every((product: Product) => {
// 自动提示product的属性,避免拼写错误
return product.stock > 0;
});
8.4 前端框架中的使用注意事项
8.4.1 React 中的性能优化
在 React 中使用every()
检测状态数组时,避免在渲染阶段执行重复计算,应使用useMemo
缓存结果。
javascript
import { useMemo } from "react";
interface Task {
id: number;
title: string;
completed: boolean;
}
function TaskList({ tasks }: { tasks: Task[] }) {
// 缓存every计算结果,仅tasks变化时重新计算
const allTasksCompleted = useMemo(() => {
return tasks.every(task => task.completed);
}, [tasks]);
return (
<div>
<h3>任务列表</h3>
{allTasksCompleted && <p>🎉 所有任务已完成!</p>}
<ul>
{tasks.map(task => (
<li key={task.id}>{task.title} - {task.completed? "已完成" : "未完成"}</li>
))}
</ul>
</div>
);
}
8.4.2 Vue 中的响应式处理
在 Vue 中使用every()
时,应将计算结果放在computed
属性中,利用 Vue 的响应式缓存机制。
javascript
<template>
<div class="order-list">
<h3>订单列表</h3>
<div v-if="allOrdersPaid" class="success-alert">
所有订单均已支付
</div>
<div v-for="order in orders" :key="order.id" class="order-item">
{{ order.name }} - {{ order.paid? "已支付" : "未支付" }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
orders: [
{ id: 1, name: "订单1", paid: true },
{ id: 2, name: "订单2", paid: false },
{ id: 3, name: "订单3", paid: true }
]
};
},
computed: {
// 计算属性缓存结果,仅orders变化时更新
allOrdersPaid() {
return this.orders.every(order => order.paid);
}
}
};
</script>
<style scoped>
.success-alert {
color: green;
margin: 10px 0;
padding: 10px;
border: 1px solid green;
}
</style>