工具: PlayGround
数组简介
在TypeScript中, 使用[]
表示数组, 它的结构:let valus: 类型名[] = 数据;
// 数字
let numList: number[] = [1, 2, 3];
// 字符串
let strList: string[] = ["hello", 'typeScript'];
// 任意类型
let data: any[] = [1, "hello", 3];
console.log(typeof(numList)); // "object"
console.log(typeof(strList)); // "object"
console.log(typeof(data)); // "object"
object
类型前文曾说过: 它表示一个非原始类型(数字,字符串,布尔)的值,主要作用于数组,对象和函数等,它是一种泛指的类型,可以包括任意类型值。
针对于 object
的对象判定是否合法,需要注意:
// array对象的判定
let array:any[] | null = [];
console.log(typeof(array)); // "object"
if (!array || array.length <= 0) {
console.error("array is null");
}
// map对象的判定
let map = {};
console.log(typeof(map)); // "object"
if (!map || Object.keys(map).length <= 0) {
console.error("map is null");
}
注:
null, undefined, NaN, false, ""
可使用 ! 进行判定
object
提供的主要接口有:
接口 | 返回值 | 描述 |
---|---|---|
constructor | Function | 构造函数相关 |
toString() | string | 返回字符串相关 |
toLocaleString() | string | |
valueOf() | Object | 返回指定对象的原始值 |
hasOwnProperty() | boolean | 判断对象是否具有指定名称的属性 |
isPrototypeOf() | boolean | 判断一个对象是否存在于另一个对象的原型链中 |
propertyIsEnumerable() | boolean | 判断指定的属性是否可枚举 |
简单的实例:
let obj = { name: "John", age: 30 };
console.log(obj.toString()); // "[object Object]"
console.log(obj.toLocaleString()); // "[object Object]"
console.log(obj.valueOf()); // { name: "John", age: 30 }
console.log(obj.hasOwnProperty("name")); // true
console.log(obj.hasOwnProperty("gender")); // false
console.log(Object.prototype.isPrototypeOf(obj)); // true
console.log(Object.prototype.isPrototypeOf({})); // true
console.log(obj.propertyIsEnumerable("name")); // true
console.log(obj.propertyIsEnumerable("toString")); // false
Array
数组的构建,同样支持使用Array
对象进行构建, 它被称为泛型数组。 源码参考:es5.d.ts
interface ArrayConstructor {
// 创建指定长度的数组, 返回any类型
new(arrayLength?: number): any[];
// 创建指定长度的数组,返回T类型
new <T>(arrayLength: number): T[];
// 创建包含元素的素组,返回T类型
new <T>(...items: T[]): T[];
isArray(arg: any): arg is any[];
readonly prototype: any[];
}
T
在TypeScript中表示泛型,方便我们编写更加通用和灵活性的代码,并使其适用于不同的类型。
const arr_1 = new Array(3);
console.log(arr_1); // [, , ]
const arr_2 = new Array<number>(3);
console.log(arr_2); // [, , ]
const arr_3 = new Array(1, 2, 3);
console.log(arr_3); // [1, 2, 3]
// 均为"object"
console.log(typeof(arr_1), typeof(arr_2), typeof(arr_3));
数组也是支持创建多维数组的, 比如:
// 使用基础类型构建
const numList = [[0, 1, 2], [0, 1, 2]];
console.log(numList); // [[0, 1, 2], [0, 1, 2]]
console.log(numList.length); // 2
// 使用Array创建
let dataList = [];
for (let i = 0; i < 2; ++i) {
let strs = [];
for (let j = 0; j < 3; ++j) {
strs.push(j);
}
dataList.push(strs);
}
console.log(dataList); // [[0, 1, 2], [0, 1, 2]]
console.log(dataList.length); // 2
关于Array
提供的常用接口如下:
接口 | 返回值 | 描述 |
---|---|---|
length | number | 返回数组长度 |
toString() | string | 返回数组的字符串 |
toLocaleString() | string | 返回数组中各个元素的本地化字符串表示 |
push() | number | 数组末尾添加新元素,并返回数组的新长度 |
pop() | T | undefined | 移除数组的最后一个元素,并返回该元素 |
concat() | T[] | 合并两个或多个数组,并返回一个新的数组 |
join() | string | 将数组的所有元素连接成一个字符串,并使用指定的分隔符进行分隔 |
reverse() | T[] | 反转数组中元素的顺序 |
shift() | T | 移除数组的第一个元素,并返回该元素 |
unshift() | number | 向数组的开头添加新元素,并返回数组的新长度 |
slice() | T[] | 返回数组中指定范围的元素 |
sort() | this | 对数组中的元素进行排序 |
splice() | T[] | 从数组中移除元素,并可以在指定位置插入新元素 |
indexOf() | number | 返回指定元素在数组中第一次出现的索引 |
lastIndexOf() | number | 返回指定元素在数组中最后一次出现的索引 |
every() | boolean | 检测数组中的所有元素是否满足指定条件 |
some() | boolean | 检测数组中是否存在满足指定条件的元素 |
forEach() | void | 遍历数组中的每个元素,并执行指定的回调函数 |
map() | U[] | 遍历数组中的每个元素,并根据回调函数的返回值创建一个新数组 |
filter() | T[] | 遍历数组中的每个元素,并返回满足指定条件的元素组成的新数组 |
reduce() | T | 使用指定的回调函数对数组中的元素进行累积计算,并返回最终的累积结果 |
reduceRight() | T | 使用指定的回调函数对数组中的元素进行逆向累积计算,并返回最终的累积结果 |
Array示例:
基本使用
let array = new Array();
for (let i = 0; i < 5; i++) {
// 插入数值
array.push(i+1);
}
console.log(array.toString()); // "1,2,3,4,5"
在开发中,增加测试数据,使用for循环难免有点麻烦,可以这样编写:
// 创建一个包含100个重复元素的数组,每个元素的数值为1
let array: number[] = Array(100).fill(1);
console.log(array);
数组遍历
let array = [1, true, "3"];
// 使用for循环
for (let i = 0; i < array.length; i++) {
console.log(i, array[i]);
}
// 使用forEach循环, 通过回调的方式获取索引和数值
array.forEach((value, index, data) => {
console.log(index, value);
});
两者相比:
for
循环需要设置起始值,结束条件和步长,使用灵活,可用于复杂的对象遍历forEach
循环需要索引值和控制逻辑,简洁易用,代码清晰,可通过回调方式对简单对象的遍历和处理
数组排序
通过sort
接口进行排序,默认是 升序 的。
const numList: number[] = [1,3,2,5,4];
// 默认为升序
numList.sort();
console.log(numList); // [1, 2, 3, 4, 5]
// 使用比较函数排序
numList.sort((a, b) => b - a);
console.log(numList); // [5, 4, 3, 2, 1]
// 元素反转
numList.reverse()
console.log(numList); // [1, 2, 3, 4, 5]
插入或删除
如果要移除或插入特定的元素相关也可以考虑unshift
和shift
相关:
// 使用Array对象
let arrObj = new Array();
console.log(arrObj); // []
// 使用 unshift 在数组开头插入元素, 并返回长度
arrObj.unshift(1);
arrObj.unshift(2);
let len = arrObj.unshift(0);
console.log(len, arrObj); // 3, [0, 2, 1]
// 使用shift移除首位置元素,并返回删除元素
let newLen = arrObj.shift();
console.log(newLen, arrObj); // 0, [2, 1]
数组去重
// 方法1: 使用push相关增加新数组
let arr: number[] = [1, 2, 2, 3, 4, 4, 5, 5];
let uniqueArr: number[] = [];
for (let i = 0; i < arr.length; i++) {
if (uniqueArr.indexOf(arr[i]) === -1) {
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
// 方法2:使用filter方法进行遍历获取新的数组
let arr: number[] = [1, 2, 2, 3, 4, 4, 5, 5];
let uniqueArr: number[] = arr.filter((value, index, self) => {
return self.indexOf(value) === index;
});
console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
// 方法3: 使用reduce方法
let arr: number[] = [1, 2, 2, 3, 4, 4, 5, 5];
let uniqueArr: number[] = arr.reduce((prev, curr) => {
if (!prev.includes(curr)) {
prev.push(curr);
}
return prev;
}, []);
console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
// 方法4: 使用set对象
let array: number[] = [1, 2, 2, 3, 4, 4, 5];
let uniqueArray: number[] = Array.from(new Set(array));
console.log(uniqueArray);
获取数组中某个元素
获取数组中的元素可以通过索引来简单获取
const arr_1 = [1, 2, 3, 4];
const arr_2 = [[1, 2, 3], [4, 5,6]];
console.log(arr_1[0], arr_2[1][0]); // 1, 4
// 如果索引错误,则返回undefined
console.log(arr_1[5], arr_2[1][10]); // undefined, undefined
也可以使用indexOf
和lastIndexOf
相关查找元素的索引位置相关
const arrObj = new Array<number>(1, 2, 2, 3);
// indexOf 查找元素首次出现的位置
const firstIndex = arrObj.indexOf(2);
console.log(firstIndex); // 1
// lastIndexOf 查找元素最后出现的位置
const lastIndex = arrObj.lastIndexOf(2);
console.log(lastIndex); // 2
// 如果查找不到,返回-1
console.log(arrObj.indexOf(0), arrObj.indexOf(0));
合并数组
可以使用contact
方法
const arr_1 = [1,2,3,4,5];
const arr_2 = [1,2,3,6,7];
// 使用concat合并数组, 原有数组不会发生改变
let newArr_1 = arr_1.concat(arr_2);
console.log(arr_1, arr_2); // [1, 2, 3, 4, 5], [1, 2, 3, 6, 7]
console.log(newArr_1); // [1, 2, 3, 4, 5, 1, 2, 3, 6, 7]
拓展下,如果想剔除重复元素,可以考虑filter
:
let arr1: number[] = [1, 2, 3];
let arr2: number[] = [2, 3, 4];
let mergedArr: number[] = [...arr1, ...arr2].filter((value, index, self) => {
return self.indexOf(value) === index;
});
console.log(mergedArr); // [1, 2, 3, 4]
再进行拓展下,使用最笨的循环方法实现:
let arr1: number[] = [1, 2, 3];
let arr2: number[] = [2, 3, 4];
// 获取排序的合并数组
function getMergeArr(originArr: any, destArr: any) {
if (originArr.length <= 0) {
return console.error("originArr is nil");
}
if (destArr.length <= 0) {
return console.error("originArr is nil");
}
let mergeArr: any = [];
// 遍历originArr
for (let i = 0; i < originArr.length; ++i) {
if (!mergeArr.includes(originArr[i])) {
mergeArr.push(originArr[i]);
}
}
// 遍历destArr
for (let i = 0; i < destArr.length; ++i) {
if (!mergeArr.includes(destArr[i])) {
mergeArr.push(destArr[i]);
}
}
return mergeArr;
}
console.log(getMergeArr(arr1, arr2)); // [1, 2, 3, 4]
最简单的方式,使用可变参数: ...
let array_1 = [1, 2, 3];
let array_2 = [3, 4, 5];
let array = [...array_1, ...array_2];
// [1, 2, 3, 3, 4, 5]
console.log(array);
Array和Map的互相转换
let map = new Map();
map.set("a", 1);
map.set("b", "hello");
map.set("c", true);
// 将map转换为数组
let mapToArray = Array.from(map);
console.log(mapToArray); // [["a", 1], ["b", "hello"], ["c", true]]
// 将数组转换为map
let arrayToMap = new Map(mapToArray);
console.log(arrayToMap); // Map (3) {"a" => 1, "b" => "hello", "c" => true}
map相关可参考博客: TypeScript 之 Map
解构赋值
这是ES6新增加的特性,算是对赋值运算符的拓展,可用于数组或对象模式匹配,然后对其变量赋值。
// 基本使用
let [a, b, c] = [1,2,3];
console.log(a, b, c); // 1, 2, 3
// 嵌套使用
let [a, [b, c]] = [1, [2, 3]];
console.log(a, b, c); // 1, 2, 3
let [A, [[B], C]] = [1, [[2], 3]];
console.log(A, B, C); // 1, 2, 3
// 忽略
let [a1, , c1] = [1, 2, 3];
console.log(a1, c1); // 1, 3
let [, b2, , d2] = [1,2, 3,4];
console.log(b2, d2); // 2, 4
let [a3, [, b3], [,,c3]] = [1, [2,3], [4,5,6]];
console.log(a3, b3, c3); // 1, 3, 6
支持不完全解构,可以做个简单了解,但不推荐使用,会有报错
// Error: Tuple type '[number]' of length '1' has no element at index '1'
let [a1, b1] = [1];
console.log(a1, b1); // 1, undefined
let [a2 = 1, b2] = [];
console.log(a2, b2); // 1, undefined
支持剩余参数,通过...参数
来设定,它会用于收集剩余的元素来创建一个新的数组
// 数组
let [a, ...b] = [1, 2, 3];
console.log(typeof(a), typeof(b)); // "number", "object"
console.log(a, b); // 1, [2, 3]
// 对象
let {age, ...params} = {
name: "ES",
age: 2023,
value: 1,
}
// 参数age被赋值,其余的都给了params
// 2023, {"name": "ES", "value": 1}
console.log(age, params);
// 函数参数,比如求和
function AddNum(...numbers: any) {
let totalValue = 0;
for (let num of numbers) {
totalValue += parseInt(num);
}
return totalValue;
}
console.log(AddNum(1, 2, 3)); // 6
console.log(AddNum(1, "2", "3")); // 6
数组扁平化
function flattenArraySome(array: any[]) {
// 判断 array 中是否有数组
for (; array.some(v => Array.isArray(v));) {
// 压扁数组
array = [].concat.apply([], array);
}
return array;
}
let array = [1, [2, [3, 4], 5], 6];
console.log(flattenArraySome(array));