JavaScript 数组操作实战:创建、类型判断与去重方案详解
本文系统梳理JavaScript数组的核心操作技巧,涵盖数组的多种创建方式、五种判断是否为数组的方法,以及类数组转数组的转换策略。重点深入解析八种数组去重方案,包括利用Set、双重循环、reduce、Map等现代语法,详细对比各方法的原理、适用场景及局限性,如NaN处理与性能差异,帮助开发者根据实际需求选择最优实现。
本文内容涵盖以下核心主题:
- 数组的创建方式
- 数组类型的判断方法
- 类数组与数组的相互转换
- 数组去重的多种实现
- 读者可根据具体业务场景灵活选用。
一、数组的创建
创建数组是基础技能,主要包含以下几种实现途径:
const arr = [1,2,3] // 数组字面量
const arr = [,,,] // 三元素空位数组(hole array)
const arr = new Array(4) // [,,,,]
const arr = new Array(4,2) // [4,2]
const arr = Array.of(1,2,3) // [1,2,3]在实际开发中,数组字面量写法是最为常用的方式。
二、判断是否为数组
判断变量是否为数组类型,主要有以下几种技术手段:
// 方法一
[1,2,3] instanceof Array
// 方法二
[1,2,3].constructor === Array
// 方法三
Object.prototype.toString.call([1,2,3]) === '[object Array]'
// 方法四
Array.isArray([1,2,3])
// 方法五(兼容写法)
function isArray(arr){
return Array.isArray ?
Array.isArray(arr):Object.prototype.toString.call(arr) === '[object Array]'
}通常情况下,isArray 方法是最为推荐且常用的解决方案。
三、类数组与数组的转换
有时遇到的数据结构并非纯数组,这类数据通常被归类为“类数组”。可以通过以下方法将其转换为真正的数组:
const x = document.querySelectorAll('a');
// 方法一
Array.prototype.slice.call(x);
// 方法二
Array.from(x);
Array.from(x,mapFn,thisArg);
// 方法三
[...x]
// 方法四
function toArray(x){
let res = []
for(item of x){
res.push(item)
}
return res
}
// 方法五
Array.apply(null,x)
// 方法六
[].concat.apply([],x)方法五和六的核心原理均依赖于 apply 的特性,即将传递给 apply 的第二个参数(无论是数组还是类数组)展开为参数列表,随后传入调用方法(如 new Array 或 concat)中执行。
四、数组去重策略
数组去重的核心逻辑在于比较元素是否相等,若相等则剔除其中一个。为确保比较的准确性,本文统一采用 Object.is 进行元素比对。
1. 基于 Set 的去重
set 具有元素唯一性的约束,因此将数组转换为 Set 对象后即可实现去重,随后再将其转换回数组格式即可。
function unique(arr){
return Array.from(new Set(arr))
// return [...new Set(arr)]
}
2. 双重循环配合 splice
外层循环遍历所有元素,内层循环从当前元素的下一个位置开始遍历。若发现相等元素,则利用 splice 移除其中一个。需注意,内层循环每次执行后必须回退一格索引,否则可能遗漏后续重复元素。
function unique(arr){
for(let i = 0;i < arr.length;i++){
for(let j = i + 1;i < arr.length;j++){
if(Object.is(arr[i],arr[j])){
arr.splice(j,1)
j--
}
}
}
return arr
}3. 新建数组配合 includes
创建一个新数组,在每次向新数组添加元素前,先检查该元素是否已存在于新数组中:
function unique(arr){
const res = []
arr.forEach((item,index) => {
// 也可以 if(res.indexOf(item) == -1),但是无法正确判断 NaN
if(!res,includes(item)){
res.push(item)
}
})
}4. 基于 reduce 配合 includes
function unique(arr){
return arr.reduce((acc,cur) => {
// return acc.includes(cur) ? acc : acc.concat(cur)
return acc.includes(cur) ? acc : [...acc,cur]
},[])
}5. 新建数组配合 sort
依据 sort 的运行机制(即对每个元素调用 toString 方法,随后在字符串层面进行排序),使得相等的元素在排序后聚集在一起。新建数组,在每次添加元素前检查其是否与前一个元素相等,若相等则视为重复元素:
function unique(arr){
arr.sort()
const res = [arr[0]]
for(let i = 1;i < arr.length;i++){
if(!Object.is(arr[i],arr[i-1])){
res.push(arr[i])
}
}
return res
}6. 新建数组配合对象属性
此方法的逻辑与“新建数组 + includes”类似。新建数组,在每次添加元素前检查该元素是否已作为对象的属性存在:
// 对象属性值可以认为是元素重复的次数
function unique(arr){
const res = []
const obj = {}
arr.forEach((item,index) => {
if(!obj[item]){
res.push(item)
obj[item] = 1
} else {
obj[item]++
}
})
return res
}此处检测的是对象的属性名,而属性名本质上是字符串,因此会判定 obj[true] 与 obj["true"] 相等,这可能导致布尔值 true 或字符串 "true" 无法正确放入新数组中。
7. 基于 Map 的去重
其本质与上述方法一致,但优势在于无需新建数组:
function unique(arr){
let map = new Map()
for(item of arr){
if(!map.has(item)){
map.set(item,true)
}
}
return [...map.keys()]
}8. 基于 filter 配合 indexOf
去除重复元素的另一种视角是保留那些索引值等于其首次出现索引值的元素。此类元素可通过 filter 进行筛选,并收集到数组中:
function unique(arr){
return arr.filter((item,index) => index === arr.indexOf(item))
}使用 indexOf 的局限性在于无法正确识别 NaN 值。
关于 JavaScript 数组常见操作技巧的介绍至此结束。如需了解更多 JavaScript 数组操作相关内容,建议查阅本站过往文章或继续浏览后续文章,感谢大家的支持!
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
