数组
创建数组
1. 字面量方式
最常见和简单的方法是使用数组字面量([]
)。
let arr: number[] = [1, 2, 3];
let strArr: string[] = ["a", "b", "c"];
2. 泛型方式
使用 TypeScript 提供的数组泛型 Array<T>
。
let arr: Array<number> = [1, 2, 3];
let strArr: Array<string> = ["a", "b", "c"];
3. 使用构造函数
通过 Array
构造函数创建数组。
let arr = new Array<number>(1, 2, 3); // [1, 2, 3]
let emptyArr = new Array<number>(5); // 创建长度为5的空数组
4. 通过 Array.of
使用 Array.of
方法创建数组,它可以避免构造函数中长度和元素的混淆。
let arr = Array.of(1, 2, 3); // [1, 2, 3]
let singleValueArr = Array.of(5); // [5]
5. 通过 Array.from
从类数组或可迭代对象创建数组。
let arr = Array.from("hello"); // ['h', 'e', 'l', 'l', 'o']
let mappedArr = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]
6. 使用扩展运算符
从已有的数组或可迭代对象创建新数组。
let original = [1, 2, 3];
let copy = [...original]; // [1, 2, 3]
7. 多维数组
创建多维数组。
let matrix: number[][] = [
[1, 2, 3],
[4, 5, 6],
];
8. 元组创建数组
元组是一种固定长度的数组,可以混合类型。
let tupleArr: [number, string, boolean][] = [
[1, "hello", true],
[2, "world", false],
];
添加元素
1. push
方法(改变原数组)
将一个或多个元素添加到数组的末尾。
let arr: number[] = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4]
arr.push(5, 6); // [1, 2, 3, 4, 5, 6]
2. unshift
方法(改变原数组)
将一个或多个元素添加到数组的开头。
let arr: number[] = [2, 3, 4];
arr.unshift(1); // [1, 2, 3, 4]
arr.unshift(-2, -1, 0); // [-2, -1, 0, 1, 2, 3, 4]
3. 索引赋值(改变原数组)
通过指定索引,将元素插入到数组的特定位置。
let arr: number[] = [1, 2, 4];
arr[2] = 3; // 替换位置 2 的值
arr[3] = 5; // 添加到数组末尾
4. splice
方法(改变原数组)
在指定位置插入元素,支持插入多个元素。
let arr: number[] = [1, 2, 5];
arr.splice(2, 0, 3, 4); // [1, 2, 3, 4, 5],从索引 2 开始插入 3 和 4
5. concat
方法
创建一个新数组,将元素添加到原数组的末尾。
let arr: number[] = [1, 2, 3];
let newArr = arr.concat(4, 5); // [1, 2, 3, 4, 5]
6. 扩展运算符
将新元素合并到数组中,生成新数组。
let arr: number[] = [2, 3];
let newArr = [1, ...arr, 4, 5]; // [1, 2, 3, 4, 5]
7. Array.from
通过生成新数组的方式添加元素。
let arr: number[] = [1, 2, 3];
let newArr = Array.from([...arr, 4]); // [1, 2, 3, 4]
8. fill
初始化(改变原数组)
创建数组时填充值,也可作为添加元素的方式。
let arr = new Array<number>(5).fill(0); // [0, 0, 0, 0, 0]
let arr2: number[] = [1, 2, 3];
arr2.fill(0); // [0, 0, 0]
arr2.fill(9, 1, 2); // [0, 9, 0]
9. set
方法(改变原数组)
设置数组的指定索引,即使索引不连续,用于稀疏数组。
let arr: number[] = [];
arr[5] = 10; // 稀疏数组:[undefined × 5, 10]
10. Object.assign
(改变原数组)
合并数组,添加新元素。
let arr: number[] = [1, 2, 3];
let newArr = Object.assign([], arr, { 3: 4 }); // [1, 2, 3, 4]
11. TypedArray
(改变原数组)
特殊场景,在处理二进制数据时,向 TypedArray
添加数据。
let arr = new Uint8Array(3);
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
删除元素
1. pop
方法(改变原数组)
删除数组的最后一个元素,并返回被删除的值。
let arr: number[] = [1, 2, 3];
let lastElement = arr.pop(); // arr: [1, 2], lastElement: 3
2. shift
方法(改变原数组)
删除数组的第一个元素,并返回被删除的值。
let arr: number[] = [1, 2, 3];
let firstElement = arr.shift(); // arr: [2, 3], firstElement: 1
3. splice
方法(改变原数组)
删除指定位置的元素,可指定数量。
let arr: number[] = [1, 2, 3, 4, 5];
let removed = arr.splice(1, 2); // 从索引 1 开始删除 2 个元素
// arr: [1, 4, 5], removed: [2, 3]
4. filter
方法
通过条件筛选元素,返回新数组,原数组不变。
let arr: number[] = [1, 2, 3, 4, 5];
let filtered = arr.filter(x => x !== 3); // [1, 2, 4, 5]
5. slice
方法
通过截取生成新数组,原数组不变。
let arr: number[] = [1, 2, 3, 4, 5];
let sliced = arr.slice(0, 2).concat(arr.slice(3)); // [1, 2, 4, 5]
6. delete
操作符(改变原数组)
删除数组中某个索引的元素,但不会更新数组长度,会留下 undefined
。
let arr: number[] = [1, 2, 3];
delete arr[1]; // arr: [1, undefined, 3]
7. length
属性截断数组(改变原数组)
通过修改 length
属性来删除末尾的元素。
let arr: number[] = [1, 2, 3, 4, 5];
arr.length = 3; // arr: [1, 2, 3]
8. 清空数组(改变原数组)
清空数组的所有元素。
方法 1: 设置 length
为 0
let arr: number[] = [1, 2, 3];
arr.length = 0; // arr: []
方法 2: 使用 splice
let arr: number[] = [1, 2, 3];
arr.splice(0, arr.length); // arr: []
方法 3: 重新赋值空数组
let arr: number[] = [1, 2, 3];
arr = []; // arr: []
9. 遍历删除
遍历数组并删除符合条件的元素。
let arr: number[] = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 3) {
arr.splice(i, 1);
i--; // 调整索引
}
} // arr: [1, 2, 4, 5]
10. Set
和扩展运算符
从数组中删除重复元素或指定元素。
let arr: number[] = [1, 2, 3, 2, 4];
let uniqueArr = [...new Set(arr)]; // [1, 2, 3, 4]
访问和查找元素
1. 按索引访问
直接通过索引访问数组中的元素。
let arr: number[] = [10, 20, 30, 40];
console.log(arr[1]); // 20
console.log(arr[-1]); // undefined
console.log(arr[arr.length - 1]); // 40
2. 使用 find
方法
查找第一个符合条件的元素。
let arr: number[] = [10, 20, 30, 40];
let found = arr.find(x => x > 25); // 30
3. 使用 findIndex
方法
查找第一个满足条件的元素索引。
let arr: number[] = [10, 20, 30, 40];
let index = arr.findIndex(x => x > 25); // 2
4. 使用 indexOf
方法
查找元素的第一个匹配索引。如果不存在,返回 -1
。
let arr: number[] = [10, 20, 30, 20];
let index = arr.indexOf(20); // 1
5. 使用 lastIndexOf
方法
查找元素的最后一个匹配索引。
let arr: number[] = [10, 20, 30, 20];
let lastIndex = arr.lastIndexOf(20); // 3
6 使用 includes
方法
检查数组是否包含某个元素,返回 true
或 false
。
let arr: number[] = [10, 20, 30];
let exists = arr.includes(20); // true
let notExists = arr.includes(40); // false
7. 使用 at
方法
ES2022 新增,支持正负索引访问数组。
let arr: number[] = [10, 20, 30];
let element = arr.at(-1); // 30
遍历元素
1. 使用 for
循环
最基础的遍历方式,按索引逐个访问元素。
let arr: number[] = [10, 20, 30];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]); // 10, 20, 30
}
2. 使用 for...of
遍历数组中的每个元素(不涉及索引)。
let arr: number[] = [10, 20, 30];
for (let value of arr) {
console.log(value); // 10, 20, 30
}
3. 使用 for...in
遍历数组的索引(不直接获取值)。
let arr: number[] = [10, 20, 30];
for (let index in arr) {
console.log(index, arr[index]); // 0 10, 1 20, 2 30
}
4. 使用 forEach
数组自带的迭代方法,可访问每个元素和索引。
let arr: number[] = [10, 20, 30];
arr.forEach((value, index) => {
console.log(index, value); // 0 10, 1 20, 2 30
});
5. 使用 while
循环
使用手动控制索引的方式遍历数组。
let arr: number[] = [10, 20, 30];
let i = 0;
while (i < arr.length) {
console.log(arr[i]); // 10, 20, 30
i++;
}
6. 使用 do...while
循环
至少执行一次遍历,适合需要初次强制运行的情况。
let arr: number[] = [10, 20, 30];
let i = 0;
do {
console.log(arr[i]); // 10, 20, 30
i++;
} while (i < arr.length);
7. 使用 map
遍历元素并返回一个新数组,同时可执行操作。
let arr: number[] = [10, 20, 30];
let doubled = arr.map(x => x * 2); // [20, 40, 60]
8. 使用 reduce
通过累加器逐个访问元素,同时可以累积结果。
let arr: number[] = [10, 20, 30];
let sum = arr.reduce((acc, val) => acc + val, 0); // 60
9. 使用 reduceRight
通过累加器从右到左逐个访问元素,同时可以累积结果。
let arr: number[] = [10, 20, 30];
let sum = arr.reduceRight((acc, val) => acc + val, 0); // 60
10. 使用 filter
遍历所有元素,并根据条件筛选出新数组。
let arr: number[] = [10, 20, 30, 40];
let filtered = arr.filter(x => x > 20); // [30, 40]
11. 使用 entries
获取数组的索引和值对。
let arr: number[] = [10, 20, 30];
for (let [index, value] of arr.entries()) {
console.log(index, value); // 0 10, 1 20, 2 30
}
12. 使用 keys
遍历数组的索引。
let arr: number[] = [10, 20, 30];
for (let key of arr.keys()) {
console.log(key); // 0, 1, 2
}
13. 使用 values
遍历数组的值(类似 for...of
)。
let arr: number[] = [10, 20, 30];
for (let value of arr.values()) {
console.log(value); // 10, 20, 30
}
14. 使用 at
方法与循环
结合正负索引进行遍历。
let arr: number[] = [10, 20, 30];
for (let i = 0; i < arr.length; i++) {
console.log(arr.at(i)); // 10, 20, 30
}
15. 使用 flatMap
适合对嵌套数组进行扁平化和遍历。
let arr: number[][] = [[10, 20], [30, 40]];
let flatMapped = arr.flatMap(x => x.map(y => y * 2)); // [20, 40, 60, 80]
其他
1. reverse
方法(改变原数组)
将数组中的元素顺序反转。
let arr: number[] = [1, 2, 3];
arr.reverse(); // [3, 2, 1]
2. sort
方法(改变原数组)
2.1 字符串排序
对数组进行原地排序,默认按照 Unicode 编码进行排序。
let strArr = ['banana', 'apple', 'cherry'];
strArr.sort();
console.log(strArr); // 输出: ['apple', 'banana', 'cherry']
2.2 数字排序
let numArr = [5, 3, 8, 1, 2];
numArr.sort();
console.log(numArr); // 输出: [1, 2, 3, 5, 8]
2.3 自定义排序
let numArr = [5, 3, 8, 1, 2];
numArr.sort((a, b) => a - b); // 升序排序
console.log(numArr); // 输出: [1, 2, 3, 5, 8]
numArr.sort((a, b) => b - a); // 降序排序
console.log(numArr); // 输出: [8, 5, 3, 2, 1]
2.4 数字字符串
let numArr = ["5", "1", "8", "10", "2"];
numArr.sort((a, b) => Number(a) - Number(b)); // 将字符串转换为数字进行比较
console.log(numArr); // 输出: ["1", "2", "5", "8", "10"]
numArr.sort((a, b) => Number(b) - Number(a)); // 降序
console.log(numArr); // 输出: [ '10', '8', '5', '2', '1' ]
3. join
方法
将数组的所有元素连接成一个字符串,使用指定的分隔符。
let arr: string[] = ["a", "b", "c"];
let result = arr.join("-"); // "a-b-c"
4. toString
方法
将数组转换为字符串(与 join
类似,默认以逗号分隔)。
let arr: number[] = [1, 2, 3];
let result = arr.toString(); // "1,2,3"
5. flat
方法
将嵌套数组展开为一维数组,可指定展开深度。
let arr: number[][] = [[1, 2], [3, [4, 5]]];
let flatArr = arr.flat(); // [1, 2, 3, [4, 5]]
let deepFlatArr = arr.flat(2); // [1, 2, 3, 4, 5]
6. isArray
静态方法
判断一个对象是否为数组。
let arr: number[] = [1, 2, 3];
console.log(Array.isArray(arr)); // true
console.log(Array.isArray({})); // false
7. copyWithin
方法(改变原数组)
在数组内部浅复制部分元素到其他位置,覆盖原有元素。
let arr: number[] = [1, 2, 3, 4, 5];
arr.copyWithin(1, 3); // [1, 4, 5, 4, 5]
8. toLocaleString
方法
将数组的所有元素转为字符串,并格式化为本地表示。
let arr: number[] = [1000, 2000];
let result = arr.toLocaleString("en-US"); // "1,000,2,000"
9. Array.prototype[@@iterator]
方法
返回一个数组的默认迭代器。
let arr: number[] = [1, 2, 3];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next().value); // 1
10. 属性 length
length
是数组的一个属性,表示数组中的元素个数。可以用来获取或设置数组的长度。
let arr = [1, 2, 3, 4];
console.log(arr.length); // 输出: 4
arr.length = 2; // 修改数组长度
console.log(arr); // 输出: [1, 2]
11. 深拷贝和浅拷贝
在 TypeScript 中,数组的深拷贝和浅拷贝主要用于确保数据独立性和完整性。以下是关于深拷贝和浅拷贝的方法总结:
浅拷贝
浅拷贝只复制数组的引用,嵌套对象和嵌套数组仍然指向原始数据。
1. 通过扩展运算符(...
)
let original = [1, 2, 3];
let shallowCopy = [...original]; // [1, 2, 3]
2. 通过 Array.prototype.slice
let original = [1, 2, 3];
let shallowCopy = original.slice(); // [1, 2, 3]
3. 通过 Array.prototype.concat
let original = [1, 2, 3];
let shallowCopy = original.concat(); // [1, 2, 3]
深拷贝
深拷贝会递归复制所有嵌套对象和数组,确保新数组与原始数组完全独立。
1. 通过 JSON.parse
和 JSON.stringify
最常见的深拷贝方式,适合纯数组(没有函数和特殊对象)。
let original = [1, { a: 2 }, [3, 4]];
let deepCopy = JSON.parse(JSON.stringify(original));
// 修改 deepCopy 不影响 original
deepCopy[1].a = 10;
console.log(original); // [1, { a: 2 }, [3, 4]]
console.log(deepCopy); // [1, { a: 10 }, [3, 4]]
2. 通过递归函数
适合自定义复杂的深拷贝需求。
function deepClone<T>(arr: T[]): T[] {
return arr.map(item =>
Array.isArray(item)
? deepClone(item) // 如果是数组,递归调用
: typeof item === 'object' && item !== null
? { ...item } // 如果是对象,解构拷贝
: item // 基本类型直接返回
);
}
let original = [1, { a: 2 }, [3, 4]];
let deepCopy = deepClone(original);
3. 通过第三方库
使用 Lodash 的 cloneDeep
安装 Lodash:
npm install lodash
使用 cloneDeep
方法:
import { cloneDeep } from "lodash";
let original = [1, { a: 2 }, [3, 4]];
let deepCopy = cloneDeep(original);
浅拷贝与深拷贝的对比
方法 | 类型 | 备注 |
---|---|---|
... | 浅拷贝 | 简单且高效,适用于浅层数组和基本类型。 |
slice | 浅拷贝 | 经典方法,适用于兼容旧版 JavaScript。 |
concat | 浅拷贝 | 类似 slice ,适合连接操作。 |
JSON.stringify | 深拷贝 | 快捷,无法处理函数、循环引用、特殊对象等。 |
自定义递归 | 深拷贝 | 灵活但需要考虑多种数据结构。 |
Lodash 的 cloneDeep | 深拷贝 | 功能强大,支持复杂对象和循环引用。 |