JavaScript数组高级玩法:从入门到放弃再到精通

前言

都2025年了,你还在用for循环遍历数组?是时候升级你的数组技能树了! 今天咱们就来深挖一下JavaScript数组的那些"不为人知"的秘密,保证让你大呼过瘾!

重新认识数组:不只是"盒子"那么简单

首先,我们要颠覆一个认知:JavaScript的数组并不是传统意义上的数组,它更像是一个"可遍历的对象"。这话怎么理解呢?

数组的两种初始化方式

js 复制代码
// 方式一:new Array() - C++/Java程序员的最爱
const arr = new Array(5);  // 指定了大小
console.log(arr); // [empty × 5]

// 方式二:数组字面量 - JavaScript原住民的选择  
const arr2 = [1, 2, 3, 4, 5];

这里就有意思了,new Array(5)创建的数组虽然有5个位置,但这些位置是"empty"状态,不是undefined

Empty vs Undefined:一个让人头大的区别

js 复制代码
const arr = new Array(5);
console.log(arr[0]); // undefined(访问时返回undefined)

// 但是用for...in遍历时
for(let key in arr){
    console.log(key, arr[key]); // 什么都不会打印!
}

为什么会这样?因为"empty"意味着这个索引键根本不存在!就像你家里有5个房间的钥匙位置,但钥匙还没造出来。

要解决这个问题,我们需要显式填充:

js 复制代码
const arr2 = new Array(5).fill(undefined);
arr2[8] = undefined; // 动态扩容,JavaScript数组的超能力!
console.log(arr2); // [undefined, undefined, undefined, undefined, undefined, empty × 3, undefined]

// 现在for...in可以遍历有值的索引了
for(let key in arr2){
    console.log(key, arr2[key]); // 0,1,2,3,4,8
}

Array的静态方法:造数组的艺术

Array.of() - 优雅的数组创建

js 复制代码
// 不用再纠结new Array的奇怪行为了
console.log(Array.of(1,2,3)); // [1, 2, 3]
// 对比一下new Array的迷惑行为
console.log(new Array(3)); // [empty × 3] 
console.log(new Array(1,2,3)); // [1, 2, 3]

Array.from() - 数组界的变形金刚

这个方法绝对是我的心头好,能把任何"类数组"转换成真正的数组:

js 复制代码
// 一行代码生成字母表,是不是很酷?
console.log(Array.from(new Array(26), (val, index) => String.fromCharCode(index + 65)));
// ['A', 'B', 'C', ..., 'Z']

第二个参数是个回调函数,类似于map,可以在转换的同时进行计算。这比先创建再map要优雅多了!

🔍 对象原型链与数组的关系

这里要聊一个容易被忽略的点:JavaScript中一切皆对象,数组也不例外。

js 复制代码
let obj = {
    name: '迪迦',
}
let obj2 = {
    skill: '迪拉修姆光流',
}
obj.__proto__ = obj2;

console.log(obj.skill); // '迪拉修姆光流'

// 遍历时会包含原型链上的属性
for(let key in obj){
    console.log(obj[key]); // '迪迦' 和 '迪拉修姆光流'
}

// 判断是否为自有属性
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('skill')); // false

// 数组也是对象,也有这个问题
const arr = new Array(5);
console.log(arr.hasOwnProperty(0)); // false(因为是empty)

这就是为什么在遍历对象时,我们经常要用hasOwnProperty来过滤原型链上的属性。

数组遍历:告别无脑for循环

forEach:最常用但有局限

js 复制代码
const names = Array.of('Alice','Bob','Charlie','David','Eve');

names.forEach(name => {
    if (name === 'Charlie'){
        console.log('Charlie is here, stop...');
        return; // 只能跳过当前迭代,不能中断整个循环
    }
    console.log('Processing:', name);
});

forEach的问题是无法中断循环,return只是跳过当前项,不是真正的break

for...of:现代JavaScript的优雅选择

js 复制代码
const arr = [1,2,3];

// 简单遍历值
for(let item of arr){
    console.log(item);
}

// 需要索引?用entries()
for(const item of arr.entries()){
    console.log(item); // [0, 1], [1, 2], [2, 3]
}

// 解构赋值,同时拿到索引和值
for(const [index, item] of arr.entries()){
    console.log(index, item);
}

for...offorEach的优势在于:

  1. 可以使用breakcontinue
  2. 可读性更好
  3. 性能略优于forEach

reduce:数组界的瑞士军刀

如果说JavaScript数组方法中只能选一个MVP,我会毫不犹豫选择reduce

js 复制代码
// 基础用法:累加
console.log([1,2,3,4,5,6].reduce((prev, curr) => {
    return prev + curr;
}, 0)); // 21

reduce的精髓在于"消灭数组,留下一个"。它在处理复杂的状态转换时特别有用,新的状态总是基于上一个状态产生。

想象一下用reduce实现:

  • 数组去重
  • 分组统计
  • 数据格式转换
  • 状态机...

简直就是函数式编程的利器!

实战建议

  1. 性能考虑:普通的计数for循环性能最好,但可读性差。在性能敏感的场景(如大数据处理)可以考虑
  2. 可读性优先 :大多数情况下,for...ofmapfilter等方法的可读性远超传统for循环
  3. 避免混用:不要在同一个项目中混用多种遍历方式,保持代码风格一致

总结

JavaScript数组远比我们想象的复杂和强大:

  • 它既有类似HashMap的key-value特性,又支持动态扩容
  • new Array()和字面量[]在某些场景下行为不同
  • 现代JavaScript提供了丰富的数组方法,告别无脑for循环
  • reduce是处理复杂数据转换的神器

下次面试官问你数组相关问题时,记得展示这些深度理解,绝对能让你脱颖而出!

相关推荐
kyriewen6 小时前
写组件文档写到吐?我用AI自动生成Storybook,同事以后直接抄
前端·javascript·面试
五点六六六7 小时前
你敢信这是非Native页面写出来的渐变效果吗🌝(底层原理解析
前端·javascript·面试
吃西瓜的年年8 小时前
TypeScript
javascript·ubuntu·typescript
熊猫_豆豆11 小时前
一个模拟四轴飞行器在随机气流扰动下悬停飞行的交互式3D仿真网页,包含飞行器建模与PID控制算法
javascript·3d·html·四轴无人机模拟飞行
来恩100312 小时前
jQuery选择器
前端·javascript·jquery
前端繁华如梦12 小时前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
CDwenhuohuo12 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
川冰ICE13 小时前
TypeScript装饰器与元编程实战
前端·javascript·typescript
AI砖家13 小时前
Vue3组件传参大全,各种传参方式的对比
前端·javascript·vue.js
希望永不加班13 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html