目录
一. 一维数组
数组是存放在连续内存空间上的相同类型数据的集合。
数组的元素无法删除,只能覆盖。
1.1 创建数组
const arr1 = [1,2,3,4,5];
const arr2 = Array(5).fill(0);// 新建数组[0,0,0,0,0]
const arr3 = new Array(5).fill(0);// 新建数组[0,0,0,0,0]
const arr4 = Array(5).fill(0).map(idx => idx + 1); // 新建数组[1,2,3,4,5]
const arr5 = new Array(1,2,3,4,5); // 新建数组[1,2,3,4,5]
1.2 遍历数组
- for循环
const arr = ['a','b','c'];
for(let idx = 0; idx < arr.length; idx ++) {
const item = arr[idx];
...
}
- forEach循环
arr.forEach((item, idx) => {
...
});
- for…of遍历(ES6)
for (let item of arr) {
...
}
或
for (let [idx, item] of arr.entries()) {
...
}
// arr.entries()等于Array Iterator [[0, 'a'], [1, 'b'], [2, 'c']]
注意:
遍历数组不要用for…in。因为for…in会遍历对象的所有可枚举属性,包括其原型链中的属性。
1.3 识别数组
参考:https://www.cnblogs.com/echolun/p/10287616.html
- Array.isArray
Array.isArray(arr) // true
- instanceof运算符
instanceof
运算符用于检查对象的原型链中是否包含指定构造函数的prototype
属性。
以arr instanceof Array
为例,该表达式会验证arr
是否由 Array构造函数创建(即Array.prototype
是否在其原型链上),若成立则返回true
。
arr instanceof Array // true
- constructor属性
JavaScript 中,对象的 constructor 属性默认指向创建该实例的构造函数。因此,只有当数组 arr 是通过原生 Array 构造函数(而非子类或其他方式)生成时,以下表达式才成立:
arr.constructor === Array; // true
- Object.prototype.toString().call()
表达式Object.prototype.toString.call(a)
通过调用原生 toString 方法返回格式化的类型字符串。
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call(123) // "[object Number]"
注意:
数组和对象的type都是’object’,不能用typeof判断是否是数组。
typeof [] === 'object' // true
typeof {} === 'object' // true
1.4 拷贝数组
1.5 Array常用方法
二. 二维数组
二维数组的每个元素是一个一维数组。
C++中,数组是提前规定了所有元素的类型和大小的,数组是存在内存中的一段连续的内存地址中的,且二维数组中的arr[0][0]、arr[0][1]…到arr[m][n]也是存在一段连续内存地址中的。假如要找arr[x],可以直接根据首项地址和元素大小算出来。
而JavaScript中,数组是一个对象,索引的对象的键值,同时数组是动态的,可以包含任何类型任何大小的元素,所以js数组是以类似链表的方式存储的,每个项都存储了下一个项的引用,而不是计算下一个项的内存地址。假如要找arr[x],需要从首项开始一路找过去。
2.1 创建二维数组
const arr1 = [
[1,0],
[1,1],
[1,2],
];
const arr2 = Array(3).fill(0).map((item, idx) => [1, idx]); // 新建数组[[1,0],[1,1],[1,2]]
const arr3 = new Array(3).fill(0);
arr3.forEach((item, idx) => {
arr3[idx] = [1,idx];
});
// 或
for (const i = 0; i < arr3.length; i ++) {
arr3[i] = [1,i];
}
为什么arr1和arr3中还要先fill再map和forEach?因为Array(5)建出来的是数组长度为3的空槽,map和forEach不访问空槽。
为什么不直接Array(3).fill([1, 0]).map((item, idx) => item[1] = idx)?因为fill传入对象的话,会导致被填充的数组每个元素都引用这个对象,之后只要改一个元素,整个数组就全都会变。
2.2 遍历二维数组
双重for循环
2.3 查找二维数组
function search(value) {
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] === value) {
return {found: true, row: i, col: j};
}
}
}
return { found: false };
}
2.4 转置二维数组
前提是二维数组的行数与列数相等。
let transposed = matrix[0].map((col, i) => matrix.map(row => row[i]));
本文参考:https://programmercarl.com/数组理论基础.html