Array.prototype.includes()方法
ECMAScript 7 Array.prototype.includes()方法
ECMAScript 7引入了Array.prototype.includes()
方法,用于判断数组是否包含某个特定元素。这个方法解决了indexOf()
方法在判断元素存在时的几个痛点,比如无法正确识别NaN
,以及需要显式检查返回值是否不等于-1。
基本语法和参数
includes()
方法的语法非常简单:
arr.includes(valueToFind[, fromIndex])
它接受两个参数:
valueToFind
:需要查找的元素值fromIndex
(可选):从哪个索引开始查找,默认为0
方法返回一个布尔值:
true
:如果找到该元素false
:如果未找到该元素
与indexOf()方法的比较
在ES7之前,我们通常使用indexOf()
方法来判断元素是否存在:
const arr = [1, 2, 3];
if (arr.indexOf(2) !== -1) {
console.log('Found');
}
includes()
方法提供了更直观的语法:
const arr = [1, 2, 3];
if (arr.includes(2)) {
console.log('Found');
}
处理NaN的特殊情况
includes()
方法的一个重大改进是它能正确处理NaN
的查找。在JavaScript中,NaN
不等于任何值,包括它自己:
console.log(NaN === NaN); // false
indexOf()
无法正确查找NaN
:
const arr = [1, NaN, 3];
console.log(arr.indexOf(NaN)); // -1 (找不到)
而includes()
可以:
const arr = [1, NaN, 3];
console.log(arr.includes(NaN)); // true
fromIndex参数的使用
fromIndex
参数指定开始搜索的位置:
const arr = [1, 2, 3, 2, 1];
// 从索引2开始搜索
console.log(arr.includes(2, 2)); // true (找到第二个2)
console.log(arr.includes(2, 3)); // false (找不到)
如果fromIndex
大于或等于数组长度,直接返回false
:
const arr = [1, 2, 3];
console.log(arr.includes(1, 3)); // false
console.log(arr.includes(1, 100)); // false
负值的fromIndex
会从数组末尾开始计算:
const arr = [1, 2, 3];
console.log(arr.includes(2, -2)); // true (从索引1开始)
console.log(arr.includes(1, -1)); // false (从索引2开始)
类型数组和类数组对象
includes()
方法也可以用于类型数组(TypedArray):
const typedArray = new Uint8Array([1, 2, 3]);
console.log(typedArray.includes(2)); // true
但对于类数组对象,需要先转换为数组:
const arrayLike = {0: 'a', 1: 'b', length: 2};
console.log(Array.prototype.includes.call(arrayLike, 'b')); // true
性能考虑
在大多数情况下,includes()
和indexOf()
的性能差异可以忽略不计。但在大型数组中进行频繁查找时,indexOf()
可能稍微快一些,因为它只需要返回第一个匹配项的索引,而includes()
需要遍历整个数组直到找到匹配项。
实际应用场景
- 简单的存在性检查:
const permissions = ['read', 'write', 'execute'];
if (permissions.includes('write')) {
// 执行写操作
}
- 表单验证:
const validExtensions = ['.jpg', '.png', '.gif'];
const fileExtension = getFileExtension(); // 假设这是一个获取文件扩展名的函数
if (!validExtensions.includes(fileExtension.toLowerCase())) {
alert('无效的文件类型');
}
- 功能检测:
// 检测浏览器是否支持某个API
const supportedAPIs = ['fetch', 'Promise', 'IntersectionObserver'];
if (!supportedAPIs.includes('IntersectionObserver')) {
// 加载polyfill
}
与其他数组方法的结合
includes()
可以与其他数组方法结合使用,创建更强大的逻辑:
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = [2, 4, 6];
// 找出numbers中不在evenNumbers中的偶数
const missingEvens = numbers.filter(
num => num % 2 === 0 && !evenNumbers.includes(num)
);
console.log(missingEvens); // []
边界情况和注意事项
- 稀疏数组:
const sparseArray = [1, , 3];
console.log(sparseArray.includes(undefined)); // false
- 对象引用:
includes()
使用严格相等(===)比较,所以对象比较的是引用:
const obj = {name: 'John'};
const arr = [{name: 'John'}, obj];
console.log(arr.includes({name: 'John'})); // false
console.log(arr.includes(obj)); // true
- 原型链上的属性:
function MyArray() {}
MyArray.prototype = Array.prototype;
const myArr = new MyArray();
myArr.push(1, 2, 3);
console.log(myArr.includes(2)); // true
浏览器兼容性和polyfill
虽然现代浏览器都支持includes()
,但在旧版浏览器中可能需要polyfill:
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (len === 0) {
return false;
}
var n = fromIndex | 0;
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
function sameValueZero(x, y) {
return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
}
while (k < len) {
if (sameValueZero(o[k], searchElement)) {
return true;
}
k++;
}
return false;
};
}
与其他语言中的类似方法比较
- Python:
arr = [1, 2, 3]
print(2 in arr) # True
- Ruby:
arr = [1, 2, 3]
puts arr.include?(2) # true
- Java:
import java.util.Arrays;
List<Integer> list = Arrays.asList(1, 2, 3);
System.out.println(list.contains(2)); // true
在框架和库中的应用
- React中的条件渲染:
const allowedRoles = ['admin', 'editor'];
const userRole = getUserRole(); // 假设这是一个获取用户角色的函数
{allowedRoles.includes(userRole) && <AdminPanel />}
- Vue中的计算属性:
new Vue({
data: {
cartItems: ['apple', 'banana', 'orange']
},
computed: {
hasBanana() {
return this.cartItems.includes('banana');
}
}
});
高级用法示例
- 实现一个不区分大小写的includes:
function caseInsensitiveIncludes(arr, value) {
return arr.some(item =>
String(item).toLowerCase() === String(value).toLowerCase()
);
}
const fruits = ['Apple', 'Banana', 'Orange'];
console.log(caseInsensitiveIncludes(fruits, 'apple')); // true
- 深度includes实现:
function deepIncludes(arr, value) {
return arr.some(item => JSON.stringify(item) === JSON.stringify(value));
}
const complexArray = [{a: 1}, {b: 2, c: [3, 4]}];
console.log(deepIncludes(complexArray, {b: 2, c: [3, 4]})); // true
与其他ES7特性的结合使用
- 与指数运算符结合:
const powers = [1, 2, 4, 8, 16];
const number = 2 ** 3; // 8
console.log(powers.includes(number)); // true
- 与async/await结合:
async function checkFeatureAvailability(features, featureName) {
if (!Array.isArray(features)) {
features = await fetchFeatures();
}
return features.includes(featureName);
}
测试用例示例
为了确保正确理解includes()
的行为,可以编写一些测试用例:
const testCases = [
{ input: [[1, 2, 3], 2], expected: true },
{ input: [[1, 2, 3], 4], expected: false },
{ input: [[1, NaN, 3], NaN], expected: true },
{ input: [['a', 'b', 'c'], 'a'], expected: true },
{ input: [[1, 2, 3], '1'], expected: false },
{ input: [[1, 2, 3], 2, 1], expected: true },
{ input: [[1, 2, 3], 1, 1], expected: false },
];
testCases.forEach(({input, expected}) => {
const result = Array.prototype.includes.apply(input[0], input.slice(1));
console.assert(
result === expected,
`Failed: [${input[0]}].includes(${input.slice(1).join(', ')}) ` +
`expected ${expected} but got ${result}`
);
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:Promise.all()方法
下一篇:指数运算符(**)