JavaScript Array数组
数组是 JavaScript 中最重要的数据结构之一,用于存储和操作有序的数据集合。JavaScript 提供了丰富的数组方法,使得数组操作变得非常便捷和强大。在本章节中,我们将深入学习 JavaScript 中的数组及其各种操作方法。
什么是数组
数组是一种特殊类型的对象,用于存储有序的元素集合。数组中的每个元素都有一个数字索引,从 0 开始。
数组的特点
- 有序性:元素按照插入顺序排列
- 索引访问:通过数字索引访问元素
- 动态性:大小可以动态改变
- 混合类型:可以存储不同类型的数据
- 引用类型:数组是对象,通过引用传递
创建数组
数组字面量
javascript
// 空数组
const emptyArray = [];
// 带元素的数组
const fruits = ["苹果", "香蕉", "橙子"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "hello", true, null, { name: "张三" }];
// 多维数组
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
console.log(fruits[0]); // "苹果"
console.log(numbers[2]); // 3
console.log(matrix[1][2]); // 6Array 构造函数
javascript
// 创建空数组
const arr1 = new Array();
const arr2 = new Array(5); // 创建长度为5的空数组
// 创建带元素的数组
const arr3 = new Array(1, 2, 3);
const arr4 = new Array("苹果", "香蕉", "橙子");
console.log(arr2.length); // 5
console.log(arr3); // [1, 2, 3]
console.log(arr4); // ["苹果", "香蕉", "橙子"]
// 注意:只有一个数字参数时创建指定长度的数组
const arr5 = new Array(3);
console.log(arr5); // [empty × 3]
console.log(arr5.length); // 3
// 使用 Array.of() 避免这个问题
const arr6 = Array.of(3);
console.log(arr6); // [3]
console.log(arr6.length); // 1Array.from()
javascript
// 从类数组对象创建数组
function example() {
return Array.from(arguments);
}
const argsArray = example(1, 2, 3);
console.log(argsArray); // [1, 2, 3]
// 从字符串创建数组
const strArray = Array.from("hello");
console.log(strArray); // ["h", "e", "l", "l", "o"]
// 从 Set 创建数组
const set = new Set([1, 2, 3, 2, 1]);
const setArray = Array.from(set);
console.log(setArray); // [1, 2, 3]
// 从 Map 创建数组
const map = new Map([["a", 1], ["b", 2]]);
const mapArray = Array.from(map);
console.log(mapArray); // [["a", 1], ["b", 2]]
// 使用映射函数
const doubled = Array.from([1, 2, 3], x => x * 2);
console.log(doubled); // [2, 4, 6]
// 创建指定长度的数组并初始化
const zeros = Array.from({ length: 5 }, () => 0);
console.log(zeros); // [0, 0, 0, 0, 0]
const indices = Array.from({ length: 5 }, (_, index) => index);
console.log(indices); // [0, 1, 2, 3, 4]数组基本操作
访问和修改元素
javascript
const colors = ["红色", "绿色", "蓝色"];
// 访问元素
console.log(colors[0]); // "红色"
console.log(colors[colors.length - 1]); // "蓝色" (最后一个元素)
// 修改元素
colors[1] = "黄色";
console.log(colors); // ["红色", "黄色", "蓝色"]
// 添加元素
colors[3] = "紫色";
console.log(colors); // ["红色", "黄色", "蓝色", "紫色"]
// 访问不存在的索引
console.log(colors[10]); // undefined数组长度
javascript
const arr = [1, 2, 3];
console.log(arr.length); // 3
// 修改 length 属性
arr.length = 5;
console.log(arr); // [1, 2, 3, undefined, undefined]
arr.length = 2;
console.log(arr); // [1, 2]
// 清空数组
arr.length = 0;
console.log(arr); // []数组方法
添加和删除元素
javascript
const fruits = ["苹果", "香蕉"];
// push() - 在末尾添加元素
const newLength = fruits.push("橙子");
console.log(fruits); // ["苹果", "香蕉", "橙子"]
console.log(newLength); // 3
// pop() - 删除末尾元素
const lastFruit = fruits.pop();
console.log(fruits); // ["苹果", "香蕉"]
console.log(lastFruit); // "橙子"
// unshift() - 在开头添加元素
const newLength2 = fruits.unshift("葡萄");
console.log(fruits); // ["葡萄", "苹果", "香蕉"]
console.log(newLength2); // 3
// shift() - 删除开头元素
const firstFruit = fruits.shift();
console.log(fruits); // ["苹果", "香蕉"]
console.log(firstFruit); // "葡萄"
// splice() - 添加/删除元素
const vegetables = ["胡萝卜", "土豆", "洋葱"];
// 在索引1处删除1个元素,然后添加"西红柿"和"黄瓜"
const removed = vegetables.splice(1, 1, "西红柿", "黄瓜");
console.log(vegetables); // ["胡萝卜", "西红柿", "黄瓜", "洋葱"]
console.log(removed); // ["土豆"]
// 只添加元素
vegetables.splice(2, 0, "青椒");
console.log(vegetables); // ["胡萝卜", "西红柿", "青椒", "黄瓜", "洋葱"]
// 只删除元素
const removed2 = vegetables.splice(1, 2);
console.log(vegetables); // ["胡萝卜", "黄瓜", "洋葱"]
console.log(removed2); // ["西红柿", "青椒"]数组连接和复制
javascript
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// concat() - 连接数组
const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4, 5, 6]
console.log(arr1); // [1, 2, 3] (原数组不变)
// 连接多个数组
const arr3 = [7, 8];
const all = arr1.concat(arr2, arr3);
console.log(all); // [1, 2, 3, 4, 5, 6, 7, 8]
// 扩展运算符连接数组
const combined2 = [...arr1, ...arr2];
console.log(combined2); // [1, 2, 3, 4, 5, 6]
// slice() - 提取数组片段(浅拷贝)
const numbers = [1, 2, 3, 4, 5];
const slice1 = numbers.slice(1, 4);
console.log(slice1); // [2, 3, 4]
console.log(numbers); // [1, 2, 3, 4, 5] (原数组不变)
// 复制整个数组
const copy = numbers.slice();
console.log(copy); // [1, 2, 3, 4, 5]
// 负索引
const slice2 = numbers.slice(-3, -1);
console.log(slice2); // [3, 4]
// 扩展运算符复制数组
const copy2 = [...numbers];
console.log(copy2); // [1, 2, 3, 4, 5]
// Array.from() 复制数组
const copy3 = Array.from(numbers);
console.log(copy3); // [1, 2, 3, 4, 5]数组搜索
javascript
const fruits = ["苹果", "香蕉", "橙子", "苹果", "葡萄"];
// indexOf() - 查找元素第一次出现的索引
console.log(fruits.indexOf("苹果")); // 0
console.log(fruits.indexOf("橙子")); // 2
console.log(fruits.indexOf("西瓜")); // -1 (未找到)
// lastIndexOf() - 查找元素最后一次出现的索引
console.log(fruits.lastIndexOf("苹果")); // 3
console.log(fruits.lastIndexOf("西瓜")); // -1 (未找到)
// includes() - 检查是否包含元素
console.log(fruits.includes("香蕉")); // true
console.log(fruits.includes("西瓜")); // false
// find() - 查找满足条件的第一个元素
const numbers = [1, 5, 10, 15, 20];
const found = numbers.find(num => num > 10);
console.log(found); // 15
const users = [
{ id: 1, name: "张三" },
{ id: 2, name: "李四" },
{ id: 3, name: "王五" }
];
const user = users.find(u => u.id === 2);
console.log(user); // { id: 2, name: "李四" }
// findIndex() - 查找满足条件的第一个元素的索引
const index = numbers.findIndex(num => num > 10);
console.log(index); // 3
// filter() - 过滤满足条件的元素
const filtered = numbers.filter(num => num > 10);
console.log(filtered); // [15, 20]
const adults = users.filter(user => user.id > 1);
console.log(adults); // [{ id: 2, name: "李四" }, { id: 3, name: "王五" }]数组遍历
javascript
const fruits = ["苹果", "香蕉", "橙子"];
// for 循环
for (let i = 0; i < fruits.length; i++) {
console.log(`${i}: ${fruits[i]}`);
}
// for...of 循环
for (const fruit of fruits) {
console.log(fruit);
}
// forEach() 方法
fruits.forEach((fruit, index) => {
console.log(`${index}: ${fruit}`);
});
// forEach() with thisArg
const obj = {
prefix: "水果:",
printFruits(arr) {
arr.forEach(function(fruit) {
console.log(this.prefix + fruit); // this 指向 obj
}, this);
}
};
obj.printFruits(fruits);
// entries() - 获取键值对
for (const [index, fruit] of fruits.entries()) {
console.log(`${index}: ${fruit}`);
}
// keys() - 获取索引
for (const index of fruits.keys()) {
console.log(index);
}
// values() - 获取值
for (const fruit of fruits.values()) {
console.log(fruit);
}数组转换
javascript
const numbers = [1, 2, 3, 4, 5];
// map() - 转换每个元素
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
const users = [
{ name: "张三", age: 25 },
{ name: "李四", age: 30 },
{ name: "王五", age: 35 }
];
const names = users.map(user => user.name);
console.log(names); // ["张三", "李四", "王五"]
const userInfos = users.map(user => ({
...user,
isAdult: user.age >= 18
}));
console.log(userInfos);
// flat() - 扁平化数组
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6]
// flatMap() - map + flat(1)
const sentences = ["hello world", "how are you"];
const words = sentences.flatMap(sentence => sentence.split(" "));
console.log(words); // ["hello", "world", "how", "are", "you"]
// join() - 连接数组元素为字符串
const fruits = ["苹果", "香蕉", "橙子"];
console.log(fruits.join()); // "苹果,香蕉,橙子"
console.log(fruits.join(" - ")); // "苹果 - 香蕉 - 橙子"
console.log(fruits.join("")); // "苹果香蕉橙子"数组排序
javascript
// sort() - 排序数组
const fruits = ["香蕉", "苹果", "橙子"];
fruits.sort();
console.log(fruits); // ["橙子", "苹果", "香蕉"] (按 Unicode 排序)
const numbers = [10, 2, 30, 4];
numbers.sort();
console.log(numbers); // [10, 2, 30, 4] (按字符串排序)
// 数字排序
numbers.sort((a, b) => a - b);
console.log(numbers); // [2, 4, 10, 30] (升序)
numbers.sort((a, b) => b - a);
console.log(numbers); // [30, 10, 4, 2] (降序)
// 对象排序
const users = [
{ name: "张三", age: 25 },
{ name: "李四", age: 30 },
{ name: "王五", age: 20 }
];
// 按年龄排序
users.sort((a, b) => a.age - b.age);
console.log(users);
// 按姓名排序
users.sort((a, b) => a.name.localeCompare(b.name));
console.log(users);
// reverse() - 反转数组
const arr = [1, 2, 3, 4, 5];
arr.reverse();
console.log(arr); // [5, 4, 3, 2, 1]数组聚合
javascript
const numbers = [1, 2, 3, 4, 5];
// reduce() - 累积计算
const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 15
// 计算平均值
const average = numbers.reduce((acc, curr, index, array) => {
acc += curr;
if (index === array.length - 1) {
return acc / array.length;
}
return acc;
}, 0);
console.log(average); // 3
// 查找最大值
const max = numbers.reduce((max, current) => Math.max(max, current));
console.log(max); // 5
// 统计元素出现次数
const fruits = ["苹果", "香蕉", "苹果", "橙子", "香蕉", "苹果"];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(count); // { 苹果: 3, 香蕉: 2, 橙子: 1 }
// reduceRight() - 从右到左累积
const result = numbers.reduceRight((acc, curr) => acc + curr, 0);
console.log(result); // 15
// every() - 检查所有元素是否满足条件
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // true
const hasNegative = numbers.every(num => num < 0);
console.log(hasNegative); // false
// some() - 检查是否有元素满足条件
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true
const allEven = numbers.some(num => num % 2 !== 0);
console.log(allEven); // true数组的现代方法
ES2022 新方法
javascript
const numbers = [1, 2, 3, 4, 5];
// at() - 支持负索引访问
console.log(numbers.at(0)); // 1
console.log(numbers.at(-1)); // 5 (最后一个元素)
console.log(numbers.at(-2)); // 4 (倒数第二个元素)
// findLast() - 从后往前查找
const lastEven = numbers.findLast(num => num % 2 === 0);
console.log(lastEven); // 4
// findLastIndex() - 从后往前查找索引
const lastEvenIndex = numbers.findLastIndex(num => num % 2 === 0);
console.log(lastEvenIndex); // 3数组分组
javascript
// groupBy (提案阶段,需要 polyfill)
// const users = [
// { name: "张三", department: "IT" },
// { name: "李四", department: "HR" },
// { name: "王五", department: "IT" }
// ];
// const grouped = users.group(user => user.department);
// console.log(grouped);
// 手动实现分组
function groupBy(array, keyFunction) {
return array.reduce((groups, item) => {
const key = keyFunction(item);
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(item);
return groups;
}, {});
}
const users = [
{ name: "张三", department: "IT" },
{ name: "李四", department: "HR" },
{ name: "王五", department: "IT" }
];
const grouped = groupBy(users, user => user.department);
console.log(grouped);数组最佳实践
1. 避免稀疏数组
javascript
// 不好的做法
const sparse = new Array(3);
sparse[0] = "第一个";
sparse[2] = "第三个";
console.log(sparse); // [ "第一个", empty, "第三个" ]
// 好的做法
const dense = Array.from({ length: 3 }, () => undefined);
dense[0] = "第一个";
dense[2] = "第三个";
console.log(dense); // [ "第一个", undefined, "第三个" ]
// 或者直接初始化
const arr = ["第一个", undefined, "第三个"];
console.log(arr); // [ "第一个", undefined, "第三个" ]2. 使用函数式方法
javascript
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 不好的做法 - 使用 for 循环
function getEvenSquares(numbers) {
const result = [];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
result.push(numbers[i] * numbers[i]);
}
}
return result;
}
// 好的做法 - 使用函数式方法
const evenSquares = numbers
.filter(num => num % 2 === 0)
.map(num => num * num);
console.log(evenSquares); // [4, 16, 36, 64, 100]3. 链式调用
javascript
const products = [
{ name: "笔记本电脑", price: 5000, category: "电子" },
{ name: "手机", price: 3000, category: "电子" },
{ name: "书籍", price: 50, category: "图书" },
{ name: "耳机", price: 200, category: "电子" }
];
// 链式调用处理数据
const result = products
.filter(product => product.category === "电子")
.filter(product => product.price > 1000)
.map(product => ({
...product,
discountPrice: product.price * 0.9
}))
.sort((a, b) => a.discountPrice - b.discountPrice)
.map(product => product.name);
console.log(result); // ["耳机", "手机", "笔记本电脑"]4. 性能优化
javascript
const largeArray = Array.from({ length: 1000000 }, (_, i) => i);
// 对于大数组,避免多次遍历
// 不好的做法
// const result = largeArray
// .filter(x => x % 2 === 0)
// .map(x => x * 2)
// .filter(x => x > 1000);
// 好的做法 - 一次遍历
const result = largeArray.reduce((acc, x) => {
if (x % 2 === 0) {
const doubled = x * 2;
if (doubled > 1000) {
acc.push(doubled);
}
}
return acc;
}, []);
// 对于简单操作,传统循环可能更快
function doubleEvenNumbers(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 2 === 0) {
result.push(arr[i] * 2);
}
}
return result;
}数组应用示例
1. 数据处理管道
javascript
class DataPipeline {
constructor(data) {
this.data = Array.isArray(data) ? data : [data];
}
// 过滤数据
filter(predicate) {
this.data = this.data.filter(predicate);
return this;
}
// 转换数据
map(transformer) {
this.data = this.data.map(transformer);
return this;
}
// 排序数据
sort(comparator) {
this.data = this.data.sort(comparator);
return this;
}
// 限制数量
limit(count) {
this.data = this.data.slice(0, count);
return this;
}
// 跳过数量
skip(count) {
this.data = this.data.slice(count);
return this;
}
// 扁平化
flat(depth = 1) {
this.data = this.data.flat(depth);
return this;
}
// 去重
unique(keyFunction) {
if (keyFunction) {
const seen = new Set();
this.data = this.data.filter(item => {
const key = keyFunction(item);
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
} else {
this.data = [...new Set(this.data)];
}
return this;
}
// 分组
groupBy(keyFunction) {
this.data = this.data.reduce((groups, item) => {
const key = keyFunction(item);
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(item);
return groups;
}, {});
return this;
}
// 获取结果
toArray() {
return this.data;
}
// 获取第一个元素
first() {
return this.data[0];
}
// 获取最后一个元素
last() {
return this.data[this.data.length - 1];
}
// 统计
count() {
return this.data.length;
}
// 检查是否为空
isEmpty() {
return this.data.length === 0;
}
}
// 使用示例
const users = [
{ name: "张三", age: 25, department: "IT", salary: 8000 },
{ name: "李四", age: 30, department: "HR", salary: 6000 },
{ name: "王五", age: 35, department: "IT", salary: 12000 },
{ name: "赵六", age: 28, department: "IT", salary: 9000 },
{ name: "钱七", age: 32, department: "HR", salary: 7000 }
];
// 构建数据处理管道
const result = new DataPipeline(users)
.filter(user => user.department === "IT")
.filter(user => user.salary > 8000)
.sort((a, b) => b.salary - a.salary)
.limit(2)
.map(user => ({
name: user.name,
salary: user.salary,
annualSalary: user.salary * 12
}))
.toArray();
console.log(result);
// [
// { name: "王五", salary: 12000, annualSalary: 144000 },
// { name: "赵六", salary: 9000, annualSalary: 108000 }
// ]
// 其他操作
const pipeline = new DataPipeline([1, 2, 2, 3, 3, 4, 5]);
console.log(pipeline.unique().toArray()); // [1, 2, 3, 4, 5]
console.log(pipeline.count()); // 5
console.log(pipeline.first()); // 1
console.log(pipeline.last()); // 52. 数组工具类
javascript
class ArrayUtils {
// 数组分块
static chunk(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
// 数组差集
static difference(array, ...values) {
const flatValues = values.flat();
return array.filter(item => !flatValues.includes(item));
}
// 数组交集
static intersection(array, ...values) {
const flatValues = values.flat();
return array.filter(item => flatValues.includes(item));
}
// 数组并集
static union(array, ...values) {
const flatValues = values.flat();
return [...new Set([...array, ...flatValues])];
}
// 数组去重(支持对象)
static unique(array, keyFunction) {
if (keyFunction) {
const seen = new Set();
return array.filter(item => {
const key = keyFunction(item);
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
return [...new Set(array)];
}
// 数组随机排序
static shuffle(array) {
const result = [...array];
for (let i = result.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[result[i], result[j]] = [result[j], result[i]];
}
return result;
}
// 获取数组中的最大值
static max(array, keyFunction) {
if (array.length === 0) return undefined;
if (keyFunction) {
return array.reduce((max, current) =>
keyFunction(current) > keyFunction(max) ? current : max
);
}
return Math.max(...array);
}
// 获取数组中的最小值
static min(array, keyFunction) {
if (array.length === 0) return undefined;
if (keyFunction) {
return array.reduce((min, current) =>
keyFunction(current) < keyFunction(min) ? current : min
);
}
return Math.min(...array);
}
// 数组求和
static sum(array, keyFunction) {
if (keyFunction) {
return array.reduce((sum, item) => sum + keyFunction(item), 0);
}
return array.reduce((sum, num) => sum + num, 0);
}
// 数组平均值
static average(array, keyFunction) {
if (array.length === 0) return 0;
const sum = this.sum(array, keyFunction);
return sum / array.length;
}
// 数组范围
static range(start, end, step = 1) {
const result = [];
if (step > 0) {
for (let i = start; i < end; i += step) {
result.push(i);
}
} else if (step < 0) {
for (let i = start; i > end; i += step) {
result.push(i);
}
}
return result;
}
// 数组填充
static fill(array, value, start = 0, end = array.length) {
const result = [...array];
for (let i = start; i < end; i++) {
result[i] = value;
}
return result;
}
// 数组压缩
static zip(...arrays) {
const minLength = Math.min(...arrays.map(arr => arr.length));
const result = [];
for (let i = 0; i < minLength; i++) {
result.push(arrays.map(arr => arr[i]));
}
return result;
}
}
// 使用示例
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 分块
console.log(ArrayUtils.chunk(numbers, 3));
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
// 差集
console.log(ArrayUtils.difference([1, 2, 3, 4, 5], [2, 4])); // [1, 3, 5]
// 交集
console.log(ArrayUtils.intersection([1, 2, 3], [2, 3, 4], [3, 4, 5])); // [3]
// 并集
console.log(ArrayUtils.union([1, 2], [2, 3], [3, 4])); // [1, 2, 3, 4]
// 去重(对象)
const users = [
{ id: 1, name: "张三" },
{ id: 2, name: "李四" },
{ id: 1, name: "张三" }
];
console.log(ArrayUtils.unique(users, user => user.id));
// 随机排序
console.log(ArrayUtils.shuffle([1, 2, 3, 4, 5]));
// 最大值和最小值
console.log(ArrayUtils.max([1, 5, 3, 9, 2])); // 9
console.log(ArrayUtils.min(users, user => user.id)); // { id: 1, name: "张三" }
// 求和和平均值
console.log(ArrayUtils.sum([1, 2, 3, 4, 5])); // 15
console.log(ArrayUtils.average(users, user => user.id)); // 1.5
// 范围
console.log(ArrayUtils.range(0, 10, 2)); // [0, 2, 4, 6, 8]
// 填充
console.log(ArrayUtils.fill([1, 2, 3, 4, 5], 0, 1, 4)); // [1, 0, 0, 0, 5]
// 压缩
console.log(ArrayUtils.zip([1, 2, 3], ["a", "b", "c"], [true, false, true]));
// [[1, "a", true], [2, "b", false], [3, "c", true]]3. 观察者模式数组
javascript
class ObservableArray extends Array {
constructor(...items) {
super(...items);
this.observers = [];
}
// 添加观察者
addObserver(observer) {
this.observers.push(observer);
}
// 移除观察者
removeObserver(observer) {
const index = this.observers.indexOf(observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}
// 通知观察者
notifyObservers(method, ...args) {
this.observers.forEach(observer => {
if (typeof observer[method] === "function") {
observer[method](this, ...args);
}
});
}
// 重写数组方法
push(...items) {
const result = super.push(...items);
this.notifyObservers("onPush", items);
return result;
}
pop() {
const result = super.pop();
this.notifyObservers("onPop", result);
return result;
}
shift() {
const result = super.shift();
this.notifyObservers("onShift", result);
return result;
}
unshift(...items) {
const result = super.unshift(...items);
this.notifyObservers("onUnshift", items);
return result;
}
splice(start, deleteCount, ...items) {
const result = super.splice(start, deleteCount, ...items);
this.notifyObservers("onSplice", start, deleteCount, items, result);
return result;
}
// 其他方法...
}
// 观察者示例
class ArrayLogger {
onPush(array, items) {
console.log(`添加了 ${items.length} 个项目:`, items);
}
onPop(array, item) {
console.log(`移除了项目:`, item);
}
onShift(array, item) {
console.log(`从开头移除了项目:`, item);
}
onUnshift(array, items) {
console.log(`在开头添加了 ${items.length} 个项目:`, items);
}
onSplice(array, start, deleteCount, items, removed) {
console.log(`在索引 ${start} 处删除了 ${deleteCount} 个项目,添加了 ${items.length} 个项目`);
if (removed.length > 0) {
console.log(`删除的项目:`, removed);
}
if (items.length > 0) {
console.log(`添加的项目:`, items);
}
}
}
// 使用示例
const observableArray = new ObservableArray(1, 2, 3);
const logger = new ArrayLogger();
observableArray.addObserver(logger);
observableArray.push(4, 5); // 添加了 2 个项目: [4, 5]
observableArray.pop(); // 移除了项目: 5
observableArray.unshift(0); // 在开头添加了 1 个项目: [0]
observableArray.shift(); // 从开头移除了项目: 0
observableArray.splice(1, 1, 10, 20); // 在索引 1 处删除了 1 个项目,添加了 2 个项目总结
JavaScript 数组的核心要点:
- 创建方式:字面量、构造函数、Array.from()、Array.of()
- 基本操作:访问、修改、添加、删除元素
- 遍历方法:forEach()、for...of、entries()、keys()、values()
- 转换方法:map()、filter()、reduce()、flat()、flatMap()
- 搜索方法:find()、findIndex()、indexOf()、includes()
- 排序方法:sort()、reverse()
- 连接方法:concat()、slice()、join()
- 现代方法:at()、findLast()、findLastIndex()
- 最佳实践:避免稀疏数组、使用函数式方法、性能优化
- 实际应用:数据处理管道、工具类、观察者模式
数组是 JavaScript 编程的基础,掌握数组的各种方法和技巧对于提高编程效率至关重要。在下一章节中,我们将学习 JavaScript 的 Number 对象。