各位程序猿/媛,大家好!我是今天的讲师,咱们今天来聊聊JavaScript里一个简单却又非常实用的数组方法:Array.prototype.includes()
。
开场白:数组中的“捉迷藏”高手
想象一下,你有一堆玩具(一个数组),你想知道里面有没有你最喜欢的变形金刚(一个元素)。 你会怎么做? 一种方法是,你一个一个地找,直到找到为止,或者找完所有玩具都没找到。includes()
方法就像一个训练有素的“捉迷藏”高手,能帮你快速地判断某个玩具(元素)是否在你的玩具堆(数组)里。
includes()
方法的基本用法
includes()
方法用于判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true
,否则返回 false
。
语法:
array.includes(valueToFind[, fromIndex])
参数:
valueToFind
: 要查找的元素值。fromIndex
(可选): 从哪个索引位置开始查找。如果为负值,则从array.length + fromIndex
索引开始搜索。 默认值为0
。
返回值:
Boolean
: 如果数组包含指定的元素,则返回true
;否则返回false
。
举个栗子(例子)说明
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.includes('banana')); // true
console.log(fruits.includes('grape')); // false
在这个例子中,我们创建了一个名为 fruits
的数组,其中包含三种水果。fruits.includes('banana')
返回 true
,因为数组中确实存在 ‘banana’。而 fruits.includes('grape')
返回 false
,因为数组中没有 ‘grape’。
fromIndex
参数:从哪里开始找?
fromIndex
参数允许你指定从数组的哪个位置开始查找。这在大型数组中特别有用,可以避免不必要的搜索。
const numbers = [1, 2, 3, 4, 5, 1, 2];
console.log(numbers.includes(2)); // true (默认从索引 0 开始)
console.log(numbers.includes(2, 2)); // true (从索引 2 开始)
console.log(numbers.includes(2, 5)); // true (从索引 5 开始)
console.log(numbers.includes(2, 6)); // true (从索引 6 开始)
console.log(numbers.includes(2, 7)); // false (从索引 7 开始)
console.log(numbers.includes(2, -1)); // false (从索引 6 开始,相当于 7-1=6)
console.log(numbers.includes(2, -2)); // true (从索引 5 开始,相当于 7-2=5)
console.log(numbers.includes(2, -6)); // true (从索引 1 开始,相当于 7-6=1)
注意,如果 fromIndex
大于或等于数组的长度,则直接返回 false
,不会进行搜索。 如果计算后的索引小于0,则从索引 0 开始。
const arr = [1, 2, 3];
console.log(arr.includes(2, 100)); // false (fromIndex 大于数组长度,直接返回 false)
console.log(arr.includes(2, -5)); // true (相当于 arr.includes(2, 0))
includes()
方法与类型判断
includes()
方法在比较元素时,使用“SameValueZero”算法。 这与 ===
(严格相等)略有不同。 最大的区别在于 NaN
的处理。
const arr = [1, NaN, 3];
console.log(arr.includes(NaN)); // true (includes() 认为 NaN 等于 NaN)
console.log(arr.indexOf(NaN)); // -1 (indexOf() 使用严格相等,认为 NaN 不等于 NaN)
console.log(NaN === NaN); // false
indexOf()
方法使用严格相等(===
)进行比较,因此 NaN === NaN
返回 false
,导致 indexOf(NaN)
返回 -1
。 而 includes()
方法则认为 NaN
等于 NaN
,所以 includes(NaN)
返回 true
。
与indexOf()
方法的对比
你可能已经注意到,indexOf()
方法也能用来判断数组是否包含某个元素。 那么,includes()
和 indexOf()
有什么区别呢?
特性 | includes() |
indexOf() |
---|---|---|
返回值 | true 或 false |
元素的索引,或者 -1 (未找到) |
NaN 处理 | 能够正确判断数组中是否包含 NaN |
无法正确判断数组中是否包含 NaN |
可读性 | 更易于理解,语义更明确 | 需要与 -1 比较才能判断是否包含 |
总的来说,如果你的目标仅仅是判断数组是否包含某个元素,includes()
更加简洁明了,并且能正确处理 NaN
。 如果你需要知道元素在数组中的索引位置,或者需要兼容不支持 includes()
的旧版本浏览器,则可以使用 indexOf()
。
代码示例:使用 includes()
简化代码
假设你需要检查一个用户的角色是否具有某个权限。 使用 indexOf()
的写法可能是这样的:
const userRoles = ['admin', 'editor', 'viewer'];
function hasPermission(role) {
return userRoles.indexOf(role) !== -1;
}
console.log(hasPermission('admin')); // true
console.log(hasPermission('author')); // false
使用 includes()
,代码会更加简洁:
const userRoles = ['admin', 'editor', 'viewer'];
function hasPermission(role) {
return userRoles.includes(role);
}
console.log(hasPermission('admin')); // true
console.log(hasPermission('author')); // false
处理对象数组
includes()
方法对于原始类型(如字符串、数字、布尔值)的数组非常有效。 但是,对于对象数组,需要特别注意,因为它比较的是对象的引用,而不是对象的内容。
const objects = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
const alice = { id: 1, name: 'Alice' };
console.log(objects.includes(alice)); // false (尽管对象的内容相同,但引用不同)
const bob = objects[1];
console.log(objects.includes(bob)); // true (引用相同)
在这个例子中,尽管 alice
对象的内容与 objects
数组中的第一个对象相同,但它们是不同的对象,具有不同的引用,因此 objects.includes(alice)
返回 false
。 只有当查找的元素与数组中的元素引用相同时,includes()
才会返回 true
。
如何判断对象数组是否包含特定属性的对象?
如果你需要判断对象数组是否包含具有特定属性的对象,可以使用 some()
方法结合 includes()
实现。
const objects = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
function hasObjectWithId(id) {
return objects.some(obj => obj.id === id);
}
console.log(hasObjectWithId(1)); // true
console.log(hasObjectWithId(3)); // false
或者,结合filter
来实现:
const objects = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
function hasObjectWithId(id) {
return objects.filter(obj => obj.id === id).length > 0;
}
console.log(hasObjectWithId(1)); // true
console.log(hasObjectWithId(3)); // false
兼容性
Array.prototype.includes()
是 ECMAScript 2016 (ES7) 中引入的。 这意味着在一些旧版本的浏览器中可能不支持。 不过,你可以使用 polyfill 来提供兼容性。
一个简单的 polyfill 实现如下:
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.includes called on null or undefined');
}
const O = Object(this);
const len = parseInt(O.length, 10) || 0;
if (len === 0) {
return false;
}
const n = parseInt(arguments[1], 10) || 0;
let k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {
k = 0;
}
}
while (k < len) {
if (searchElement === O[k]) {
return true;
}
k++;
}
return false;
};
}
这段代码检查浏览器是否支持 includes()
方法。 如果不支持,则会添加一个 includes()
方法的实现。
总结
Array.prototype.includes()
是一个简单而强大的数组方法,用于判断数组是否包含某个元素。 它比 indexOf()
更加易于理解,并且能正确处理 NaN
。 在编写代码时,根据你的需求选择合适的方法。 如果只需要判断数组是否包含某个元素,includes()
通常是更好的选择。 如果需要兼容旧版本浏览器,可以使用 polyfill。
练习题
- 编写一个函数,接收一个数组和一个值作为参数,如果数组包含该值,则返回
true
,否则返回false
。使用includes()
方法实现。 - 编写一个函数,接收一个对象数组和一个属性名作为参数,判断数组中是否包含具有该属性的对象。
- 在不支持
includes()
方法的浏览器中测试你编写的 polyfill。
希望今天的讲解对大家有所帮助! 感谢各位的聆听!下课!