> 技术文档 > JS数组(超详细)_js 数组

JS数组(超详细)_js 数组

JavaScript 数组(Array)——超详细指南

JavaScript 中的数组是一种可变、动态、基于索引的列表结构,底层实现为对象(Object)的特殊形式,既具备序列特征,也保留普通对象的灵活性。下面从基础概念、创建方式、核心属性与方法、遍历、性能与底层机制、进阶技巧等方面做全面解析。


一、数组的基本概念

  1. 索引与长度

    • 数组索引从 0 开始,到 length - 1 结束。
    • length 属性始终比最大索引值大 1;写入 arr[length] 会自动增长长度;手动设置 length 可截断或扩展数组。
  2. 稀疏数组

    • 数组可以包含“空位”(empty slots),即跳过某些索引。
    • 空位与 undefined 不同:arr = [1, , 3]1 in arr === false,但 arr[1] === undefined
  3. 数组即对象

    • 底层类型:typeof [] === \'object\'
    • 可视为具备数字键和 length 属性的对象,索引键会被自动更新 length

二、创建与初始化

// 字面量let a = [];  // 空数组let b = [1, 2, 3];  // 有初始值let sparse = [1, , 3]; // 稀疏数组// 构造函数let c = new Array(); // 等价于 []let d = new Array(5); // [  ]let e = new Array(1, 2, 3); // [1,2,3]// Array.from / Array.oflet fromStr = Array.from(\'abc\'); // [\'a\',\'b\',\'c\']let fromMap = Array.from({0:\'x\',1:\'y\', length:2});let ofArr = Array.of(5);  // [5]
  • 注意new Array(5) 会创建长度为 5 的稀疏数组;而 Array.of(5) 则创建含一个元素 5 的普通数组。

三、核心属性与方法

3.1 属性

  • length:只读表象,可写会改变数组大小。

3.2 通用方法

方法 作用 push(...items) 尾部插入元素,返回新长度 pop() 移除尾部元素,返回该元素 unshift(...items) 头部插入元素,返回新长度 shift() 移除头部元素,返回该元素 splice(start, deleteCount, ...items) 任意位置增删元素,返回被删除的子数组 slice(begin?, end?) 返回浅拷贝子数组 concat(...arrays_or_values) 合并数组/值,返回新数组 indexOf(item, fromIndex?) 查找元素首次索引,未找到返回 -1 lastIndexOf(item, fromIndex?) 查找元素最后索引 includes(item, fromIndex?) 是否包含该元素,返回布尔

3.3 迭代与映射

方法 作用 forEach(fn) 遍历(无返回值) map(fn) 返回映射后新数组 filter(fn) 返回满足条件子集新数组 reduce(fn, initialValue?) 累积计算,返回单一值 reduceRight(fn, initialValue?) 从右向左累积计算 find(fn) 返回第一个满足条件的元素 findIndex(fn) 返回第一个满足条件元素的索引 some(fn) 是否存在满足条件的元素 every(fn) 是否所有元素都满足条件 flat(depth=1) 展平多维数组 flatMap(fn) 等同于先 mapflat(1)

3.4 排序与组合

  • sort(compareFn?):原地排序;默认将元素转为字符串按 Unicode 排序。
  • reverse():原地反转数组。

四、遍历方式对比

let arr = [\'a\',\'b\',\'c\'];// 1. 经典 forfor (let i = 0; i < arr.length; i++) { /* arr[i] */ }// 2. for…of(ES6)for (const item of arr) { /* item */ }// 3. forEacharr.forEach((item, idx) => { /* … */ });// 4. for…in (不推荐)for (const key in arr) { /* key: 索引或自定义属性名 */ }// 5. 迭代器与展开const iterator = arr[Symbol.iterator]();iterator.next(); // {value:\'a\', done:false}const copy = [...arr]; // 解构复制
  • 推荐 for…of 与数组方法链式调用,保持简洁、可读。

五、底层机制与性能

  1. 连续内存 vs. 稀疏

    • V8 对“连续元素”(dense)数组做优化,存储在连续内存块;
    • 稀疏数组或含混合类型(integer key 与非整数 key)会降级为哈希表(Dictionary mode),访问速度变慢。
  2. 隐藏类(Hidden Class)与 Inline Caches

    • JS 引擎通过隐藏类优化对象访问;频繁改变数组形态(如切换稠密/稀疏模式、加入自定义属性)会触发隐藏类转变,影响性能。
  3. 避免频繁扩大

    • 使用 push 比直接修改高索引(如 arr[10000] = x)更友好;
    • 预先设置初始长度 new Array(n),然后填充,也有助于性能。
  4. TypedArray

    • 针对数值密集型场景,可使用 Int8ArrayFloat64Array 等固定长度、同质化的数组视图,性能与内存表现优异。

六、 Array-like 对象 与 转换

  • Array-like:拥有 length 属性与数值键,但不具备数组方法,如 DOM NodeList、函数的 arguments

  • 转为真数组:

    const list = document.querySelectorAll(\'div\'); // NodeListconst arr = Array.from(list);// 或者const arr2 = [].slice.call(list);

七、进阶技巧

  1. 链式调用

    const result = arr .filter(n => n % 2 === 0) .map(n => n * 2) .reduce((acc, x) => acc + x, 0);
  2. 去重

    const uniq = [...new Set(arr)];
  3. 分组

    const groups = arr.reduce((acc, item) => { const key = keyFn(item); (acc[key] ||= []).push(item); return acc;}, {});
  4. 数组填充

    const a = Array(5).fill(0); // [0,0,0,0,0]const b = Array.from({length:5}, (_,i)=>i); // [0,1,2,3,4]
  5. 并行控制(Promise 数组合并)

    const promises = urls.map(fetch);const responses = await Promise.all(promises);
  6. 多维数组

    const matrix = Array.from({ length: m }, () => Array(n).fill(0));

八、小结

  • JavaScript 数组表面看“简单”,底层却兼具对象通用性与列表特征。
  • 熟练掌握创建、遍历与常用方法,注意“稠密/稀疏”与“隐藏类”对性能的影响。
  • 结合 ES6+ 特性(for…of、拓展运算符、解构、Array.fromSet 等),可写出优雅、高效、可读的数组逻辑。

希望这份“超详细”指南能帮助你全面理解和高效使用 JavaScript 数组。若有更深入的场景或疑问,欢迎继续交流!

玻璃科普知识