数组基础

数组创建

数组是存储有序数据的集合。

数组字面量

// 空数组
const empty = [];

// 带初始值
const numbers = [1, 2, 3, 4, 5];

// 混合类型
const mixed = [1, "东巴文", true, null, { name: "JS" }];

// 多维数组
const matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

Array构造函数

// 创建空数组
const arr1 = new Array();

// 指定长度
const arr2 = new Array(5);  // [empty × 5]

// 指定元素
const arr3 = new Array(1, 2, 3);  // [1, 2, 3]

// 注意:单个数字参数是长度,不是元素
const arr4 = new Array(5);    // 长度为5
const arr5 = new Array("5");  // ["5"]

Array.of

// Array.of:总是创建包含参数的数组
const arr1 = Array.of(5);      // [5]
const arr2 = Array.of(1, 2, 3); // [1, 2, 3]
const arr3 = Array.of("东巴文"); // ["东巴文"]

Array.from

// 从类数组创建
const arr1 = Array.from("东巴文");  // ["东", "巴", "文"]

// 从arguments创建
function foo() {
    const args = Array.from(arguments);
}

// 从Set创建
const set = new Set([1, 2, 2, 3]);
const arr2 = Array.from(set);  // [1, 2, 3]

// 从Map创建
const map = new Map([[1, "a"], [2, "b"]]);
const arr3 = Array.from(map);  // [[1, "a"], [2, "b"]]

// 带映射函数
const arr4 = Array.from([1, 2, 3], x => x * 2);  // [2, 4, 6]

数组长度

每个数组都有length属性。

length属性

const arr = [1, 2, 3, 4, 5];
console.log(arr.length);  // 5

// length是可写的
arr.length = 3;
console.log(arr);  // [1, 2, 3]

arr.length = 0;
console.log(arr);  // [](清空数组)

动态增长

const arr = [1, 2, 3];
arr[10] = 11;
console.log(arr.length);  // 11
console.log(arr);  // [1, 2, 3, empty × 7, 11]

length的应用

// 清空数组
const arr = [1, 2, 3];
arr.length = 0;

// 截断数组
const arr2 = [1, 2, 3, 4, 5];
arr2.length = 3;  // [1, 2, 3]

// 添加元素
const arr3 = [1, 2];
arr3[arr3.length] = 3;  // 相当于push

数组访问

索引访问

const arr = ["东", "巴", "文"];

console.log(arr[0]);  // "东"
console.log(arr[1]);  // "巴"
console.log(arr[2]);  // "文"
console.log(arr[3]);  // undefined

// 负索引(ES2022)
console.log(arr.at(-1));  // "文"
console.log(arr.at(-2));  // "巴"

at方法

const arr = ["东", "巴", "文"];

// 正索引
arr.at(0);   // "东"
arr.at(1);   // "巴"

// 负索引(从末尾开始)
arr.at(-1);  // "文"
arr.at(-2);  // "巴"
arr.at(-3);  // "东"
arr.at(-4);  // undefined

修改元素

const arr = [1, 2, 3];

arr[0] = 10;
console.log(arr);  // [10, 2, 3]

arr[5] = 6;
console.log(arr);  // [10, 2, 3, empty × 2, 6]

数组遍历

for循环

const arr = ["东", "巴", "文"];

// 传统for循环
for (let i = 0; i < arr.length; i++) {
    console.log(i, arr[i]);
}

// 缓存长度(性能优化)
for (let i = 0, len = arr.length; i < len; i++) {
    console.log(arr[i]);
}

for...of

const arr = ["东", "巴", "文"];

for (const item of arr) {
    console.log(item);
}
// 东
// 巴
// 文

// 获取索引
for (const [index, item] of arr.entries()) {
    console.log(index, item);
}

forEach

const arr = ["东", "巴", "文"];

arr.forEach((item, index, array) => {
    console.log(index, item);
});

// 注意:forEach无法中断
// 使用some或every可以模拟中断
arr.some((item, index) => {
    if (index === 1) return true;  // 中断
    console.log(item);
});

for...in(不推荐用于数组)

const arr = ["东", "巴", "文"];

for (const index in arr) {
    console.log(index, arr[index]);
}

// 问题:会遍历自定义属性
arr.custom = "自定义";
for (const index in arr) {
    console.log(index);  // 0, 1, 2, custom
}

遍历方法对比

方法 获取索引 可中断 this 东巴文建议
for 性能优先
for...of 简洁优先
forEach 可指定 一般遍历
for...in 不用于数组

稀疏数组

稀疏数组是含有空位的数组。

创建稀疏数组

// 构造函数
const arr1 = new Array(5);  // [empty × 5]

// 删除元素
const arr2 = [1, 2, 3];
delete arr2[1];  // [1, empty, 3]

// 跳过索引
const arr3 = [1, , 3];  // [1, empty, 3]
arr3[10] = 11;  // [1, empty, 3, empty × 6, 11]

空位与undefined的区别

const arr = [1, , 3];  // 稀疏数组
const arr2 = [1, undefined, 3];  // 非稀疏数组

console.log(1 in arr);   // false(空位)
console.log(1 in arr2);  // true(undefined)

// forEach跳过空位
arr.forEach(x => console.log(x));  // 1, 3

// for...of也会跳过
for (const x of arr) {
    console.log(x);  // 1, 3
}

// map跳过空位
const mapped = arr.map(x => x * 2);  // [2, empty, 6]

填充空位

const arr = new Array(5);

// fill填充
arr.fill(0);  // [0, 0, 0, 0, 0]

// from创建
const arr2 = Array.from({ length: 5 }, () => 0);

// 展开运算符
const arr3 = [...new Array(5)].map(() => 0);

类数组对象

类数组对象具有length属性和索引,但不是真正的数组。

常见类数组

// arguments
function foo() {
    console.log(arguments);  // Arguments对象
    console.log(arguments.length);
}

// NodeList
const nodes = document.querySelectorAll("div");  // NodeList

// HTMLCollection
const children = document.body.children;  // HTMLCollection

// 字符串
const str = "东巴文";  // 类数组

转换为数组

// Array.from
const arr1 = Array.from(arguments);

// 展开运算符
const arr2 = [...arguments];

// slice
const arr3 = Array.prototype.slice.call(arguments);

// Array.from带映射
const arr4 = Array.from(arguments, x => x * 2);

判断是否为数组

// Array.isArray(推荐)
Array.isArray([1, 2, 3]);  // true
Array.isArray("123");      // false

// instanceof(有跨框架问题)
[1, 2, 3] instanceof Array;  // true

// Object.prototype.toString
Object.prototype.toString.call([1, 2, 3]);  // "[object Array]"

类数组应用

// 将arguments转为数组
function sum() {
    const args = Array.from(arguments);
    return args.reduce((a, b) => a + b, 0);
}

// 操作DOM节点列表
const divs = document.querySelectorAll("div");
const divArray = Array.from(divs);
divArray.forEach(div => div.style.color = "red");

// 字符串处理
const chars = Array.from("东巴文");
console.log(chars);  // ["东", "巴", "文"]

数组判断

Array.isArray

// 最可靠的方法
Array.isArray([1, 2, 3]);     // true
Array.isArray({ length: 3 }); // false
Array.isArray("123");         // false
Array.isArray(null);          // false
Array.isArray(undefined);     // false

其他方法

// instanceof
[1, 2, 3] instanceof Array;  // true
// 问题:跨iframe时可能失败

// constructor
[1, 2, 3].constructor === Array;  // true
// 问题:constructor可以被修改

// Object.prototype.toString(最通用)
function isArray(value) {
    return Object.prototype.toString.call(value) === "[object Array]";
}

下一步

掌握了数组基础后,让我们继续学习:

  1. 数组方法 - 掌握数组方法
  2. 数组高级应用 - 数组高级技巧
  3. 对象属性 - 深入对象

东巴文(db-w.cn) - 让编程学习更简单

📦 东巴文寄语:数组是JavaScript中最常用的数据结构,掌握数组的创建、访问、遍历是基础中的基础。理解稀疏数组和类数组对象,能让你更好地处理各种边界情况。在 db-w.cn,我们帮你打好每一个基础!