「枯燥的数组知识一网打尽!轻松学会JavaScript的数组操作」
前言
Array(数组)是编程中常见的数据结构之一。本文基于JavaScript介绍了一维数组、二维数组和多维数组的概念和用法,以及对象数组的应用和使用方法。此外,还介绍了JavaScript中常用的处理对象数组的方法。
Array数组
JavaScript中对数组的标准定义:一个用来存储元素的线性集合。 元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。 JavaScript中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性,索引可能是整数。但数字索引会在内部被转换为字符串,因为JavaScript对象中的属性名必须是字符串。JavaScript中的数组效率上不如其他语言高。 java语言如果数组越界,会出现异常,然而js里的数组是一个特殊的对象,一般情况下是允许越界的。
const arr = [1, 2, 3];
arr[-1] = 4;
console.log(arr)
数组的使用方法
创建数组
通过[]操作符声明一个数组变量(推荐,效率更高)
const arr=[];
通过数组的属性length可知创建了一个长度为0的空数组。 这种创建方式也可以在[]中放入一组元素
const arr=[1,2,3,4,5];
console.log(arr.length)//5
调用Array的构造函数创建数组
const arr=new Array()
console.log(arr.length)//0
和1一样也可以在调用构造函数的时候传一个参数指定数组的长度。
使用Array.from()
Array.from()方法可以从一个类数组或可迭代对象创建一个新的数组实例。 这个方法还可以接受一个映像函数作为第二个参数,用于初始化数组元素。
let arr = Array.from({ length: 3 }, () => 0);
console.log(arr); // [0, 0, 0]
使用展开运算符和Array()
结合使用展开运算符(...)和 Array() 构造函数来创建并初始化数组。
let arr = [...Array(3)].map(() => 0);
console.log(arr); // [0, 0, 0]
数组元素不必是同一种数据类型
const objects=[1,"zhangsan",true,null]
控制台console.log(objects)结果截图
Array.isArray()可以判断一个对象是否是数组。
Array.isArray(objects)//true
console.log(Array.isArray('[]'));
// Expected output: false(字符串'[]'不是数组)
读写函数
[]操作符
[]操作符可以把数据赋给数组,也可以用来读取数组中的元素。 下面循环实现1-10赋给数组nums
var nums=[];
for(let i=0;i<10;i++){
nums[i]=i+1
}
下面用[]读取数组中的元素
const nums=[1,2,3]
const sum=nums[0]+nums[1]+nums[2]
console.log(sum)//6
字符串生成数组
split()
调用字符串对象的split()方法可以生成数组。
const sentence="zhang san is a extrajudicial fanatics"
const words=sentence.split("");
for(let i=0;i<words.length;++i){
console.log(words[i])
}
下面的代码和上面的代码一样,只是没有循环而已
const sentence = "zhang san is a extrajudicial fanatics"
const words = sentence.split("");
console.log(words)
控制台打印的 words是数组
浅拷贝和深拷贝
把一个数组赋值给另一个数组,只是给被赋值的数组增加了一个新的引用。通过原来的引用修改数组的值,另外一个引用也会感知到这个变化。
const nums = [];
for (let i = 0; i < 10; i++) {
nums[i] = i + 1;
}
const same = nums;
console.log(same)
在上面的代码中,新数组依然指向原来的数组,这种行为称为浅拷贝。
下面来演示深拷贝,将原数组中的每一个元素都复制一份到新数组中。
function copy(arr1, arr2) {
for (let i = 0; i < arr1.length; i++) {
arr2[i] = arr1[i];
}
}
const nums = [];
for (let i = 0; i < 10; i++) {
nums[i] = i + 1;
}
const same = [];
copy(nums, same);
nums[0] = 66;
console.log(same[0])//1
将nums中的值复制给same,修改nums中的值不会影响same中的值的变化。
存取函数
JavaScript提供了一组用来访问数组元素的函数,叫做存取函数。 存取函数返回目标数组的某种变体。 常用的存取函数有下面几种
查找元素
indexOf
indexOf()是常用的存取函数之一。 用来查找传进来的参数在目标数组中是否存在。 目标数组包含该参数返回该元素在数组中的索引,不包含返回-1.
var names = ["zha", "san", "lilly"];
var position = names.indexOf("zha");
if (position >= 0) {
console.log("存在" + "在索引" + position)
} else {
console.log("不存在")
}
lastIndexOf()
lastIndexOf()该函数返回与参数相同元素中最后一个元素的索引,无相同元素,返回-1.
由已有数组创建新数组
concat()方法合并多个数组创建一个新数组 一个数组.concat(另一个数组) splice()方法截取一个数组的子集创建一个新数组。 一个数组.splice(起始索引,截取长度)
可变函数
JavaScript使用可变函数可以不引用数组中某个元素,就能改变数组内容。
为数组添加元素
为数组添加元素可以使用push(),unshift() push()会将元素添加到数组末尾(也可以使用数组的length属性为数组添加元素,但push()方法更可观 unshift()会将元素添加到数组开头
为数组删除元素
pop()删除数组末尾的元素 shift()删除数组开头的元素 pop和shift方法都将删除的元素作为方法的返回值返回,因此可以使用一个变量保存删除的元素
const arr = [1, 2, 3, 4, 5];
const a = arr.pop();
console.log("删除后的数组", arr, "删的元素", a)
从数组中间位置添加或者删除元素
splice方法为数组添加元素的语法 一个数组.splice(起始索引,需要删除的元素个数,想要添加进数组的元素) 添加元素的时候第二个参数设置为0
const arr = [1, 2, 3, 4, 5];
// arr.splice(1, 0, 6, 7, 9)
arr.splice(1, 2)
console.log(arr)
下面是splice方法为数组添加元素和删除元素的两个控制台输出截图
为数组排序
reverse()将数组中元素的顺序进行翻转 sort()对于元素是字符串类型的数组非常好使,如果要使用sort方法排序数字型元素,可以在调用sort方法时传入一个大小比较函数,排序时,sort()方法将会根据该大小比较函数比较数组中两个元素的大小,从而决定整个数组的顺序。
const nums = [10, 1, 23, 65, 26, 89];
function compare(num1, num2) {
return num1 - num2;
}
nums.sort(compare)
console.log(nums)
数组中的元素从小到大排序(升序排序)
我在做算法题的时候用到的最多的就是nums.sort((a,b)=>a-b),将nums数组中的元素从小到大排序。
迭代器方法
迭代器方法对数组中每个元素应用一个函数们可以返回一个值,一组值或者一个新数组。
不生成新数组的迭代器方法
这种迭代器方法不产生任何新数组,对于数组中的每个元素执行某种操作或者返回一个值
forEach()
forEach接收一个函数作为参数,对数组中每个元素使用该函数。 eg.将nums数组中的元素翻倍
const nums = [10, 1, 23, 65, 26, 89];
function double(a) {
console.log(a * 2)
}
nums.forEach(double);
every()
every()方法接受一个返回值为布尔类型的函数,对数组中每个元素使用该函数
function isEven(num) {
return num % 2 == 0;
}
const nums = [2, 4, 6, 8, 10];
const even = nums.every(isEven);
if (even) {
console.log("全是偶数")
} else {
"不全是偶数"
}
对于nums数组中的所有元素,isEven函数返回值true,所以every方法返回true 控制台输出全是偶数。
some()
some方法接受一个返回值为布尔类型的函数,只要有一个元素使得函数返回true,该方法就返回true。
reduce()
reduce() 方法对数组中的每个元素按序执行一个提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。
第一次执行回调函数时,不存在“上一次的计算结果”。如果需要回调函数从数组索引为 0 的元素开始执行,则需要传递初始值。否则,数组索引为 0 的元素将被用作初始值,迭代器将从第二个元素开始执行(即从索引为 1 而不是 0 的位置开始)。
const array1 = [1, 2, 3, 4];
// 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = array1.reduce(
(accumulator, currentValue) => accumulator + currentValue,
initialValue,
);
console.log(sumWithInitial);
// Expected output: 10
reduce方法还可以用来将数组中的元素连接成一个长的字符串
function concat(accumulatedString,item){
return accumulatedString+item;
}
var words=["hello","hahahah","buzhi","shuosha"];
var sentence=words.reduce(concat);
console.log(sentence)
reduceRight()
和reduce方法不同的是,它从右到左执行,基于上面的代码使用reduce可以实现翻转数组中的元素。
生成新数组的迭代器方法
map()
map()和forEach有点像,对数组中每个元素使用某个函数,区别是map会返回一个新的数组。 示例1:map()结合diy函数实现分数数组中每个分数加5
var grades = [77, 65, 87, 98, 56]
function curve(grade) {
return grade += 5;
}
const newgrades = grades.map(curve);
console.log(newgrades)
输出数组中每个单词的首字母
var words = ["hello", "hahahah", "buzhi", "shuosha"];
function first(a) {
return a[0];
}
var newq = words.map(first);
console.log(newq);
使用join方法并传入一个空字符串作为参数可以清除连接每个数组元素的逗号,
console.log(newq.join(""));
打印输出hhbs
filter()
filter会生成一个新数组,创建给定数组的一部分的浅拷贝(新数组和原始数组引用同一内存地址) 示例:输出所有长度大于5的单词
var words = ["hello", "hahahah", "buzhi", "shuosha"];
const newq = words.filter((a) => a.length > 5);
console.log(newq);
二维数组和多维数组
JavaScript只支持一维数组,但是通过在数组里保存数组元素的方式来创建多维数组。JavaScript中的二维数组可以用来表示矩阵,网格或者任何需要行和列的数据结构。 二维数组在编程面试中经常出现,尤其是在处理矩阵相关的问题时。例如:
- 矩阵相关: 给定一个 n x n 的二维矩阵,要求原地旋转 90 度。
- 岛屿数量: 给定一个由'1'(陆地)和'0'(水)组成的二维网格,计算岛屿的数量。
- 动态规划: 求解最大子数组和问题。 掌握二维数组的操作对于解决这些问题至关重要,因此了解如何在JavaScript 中有效地生成和操作二维数组是非常有用的。
创建二维数组
嵌套循环
直观易懂但是代码有嗲长。
function create2DArray(m, n) {
//创建一个长度为 m 的一维数组 arr,用于存储二维数组的行
let arr = new Array(m);
//外层循环遍历二维数组的行(m 行)
for (let i = 0; i < m; i++) {
//在外层循环内部,为每一行创建一个长度为 n 的一维数组,用于存储该行的元素。(在每个数组里面装数组)
arr[i] = new Array(n);
//内层循环遍历当前行的列(n 列)
for (let j = 0; j < n; j++) {
//在内层循环内部,为当前行的每一列元素赋初始值为 0
arr[i][j] = 0; // 或其他初始值
}
}
console.log(arr)
}
create2DArray(3, 3);
运行截图如下
练习:创建一个n行一列的二维数组。
先创建一个数组,让数组中的每个元素也是一个数组。
const twoarr = [];
for (const i = 0; i < 5; i++) {
twoarr[i] = [];
}
console.log(twoarr)
上面代码中有一个错误就是数组Uncaught TypeError: Assignment to constant variable.原因是在循环中使用const定义了变量且存在初始值,后来遍历过程中修改了i的值,所以报错了。
基础知识 使用const定义的常量必须赋初值,不能修改它的值。 使用let定义的变量可以进行赋值操作,且可以不赋初值。 所以正确代码如下
const twoarr = [];
for (let i = 0; i < 5; i++) {
twoarr[i] = [];
}
console.log(twoarr)
使用Array.from()
Array.from可以根据给定的参数创建一个新数组,map()对数组的每个元素进行处理。 这个方法代码更加简洁,但可能需花费时间来理解这种写法。
function create2DArray(m, n) {
return Array.from({ length: m }, () => Array.from({ length: n }, () => 0));
}
Array.fill()和map()
一个语义化且非常简洁的写法,有点难度
function create2DArray(m, n) {
return Array(m)
.fill()
.map(() => Array(n).fill(0));
}
使用展开运算符和map()
使用展开运算符(...)(用来展开数组)和 map() 创建一个包含 m 行 n 列的二维数组,并用指定的初始值填充每个元素。这种方法在 ES6 中使用更加简洁和优雅,利用了新的语法特性和数组方法。
function create2DArray(m, n) {
return [...Array(m)].map(() => Array(n).fill(0));
}
处理二维数组的元素
遍历数组
遍历二维数组可以简单分为按行访问和按列访问。 按行访问二维数组,外层循环对应列,内层循环对应行 下面的代码是按行访问的五行三列的二维数组
function create2DArray(m, n) {
var a = Array.from({ length: m }, () => Array.from({ length: n }, () => (Math.random() * 10)));
for (let i = 0; i < a.length; i++) {
let innerArrayLength = a[i].length;
for (let j = 0; j < innerArrayLength; j++) {
console.log("[" + i + "," + j + "] = " + a[i][j]);
}
}
}
create2DArray(5, 3)
下面是按照列访问二维数组,外层循环对应行,内层循环对应列。
function create2DArray(m, n) {
var a = Array.from({ length: m }, () => Array.from({ length: n }, () => (Math.random() * 10)));
for (let j = 0; j < a[0].length; j++) {
for (let i = 0; i < a.length; i++) {
console.log("[" + i + "," + j + "] = " + a[i][j]);
}
}
}
create2DArray(5, 3)
对于参差不齐的数组(每行元素的个数彼此不同),JavaScript表现良好,因为每一行的长度是可以通过计算得到的。
下面通过代码展示,在数组grades中,每个学生的成绩个数不一样,无需修改代码依然可以正确算出成绩的平均分。
let grades = [[89, 28], [67, 34, 98], [72, 34, 43, 87]];
let total = 0;
let average = 0;
for (let i = 0; i < grades.length; i++) {
for (j = 0; j < grades[i].length; j++) {
total += grades[i][j];
}
average = total / grades[i].length;
console.log("学生" + (i + 1) + "平均分" + average.toFixed(2))
}
对象数组
上面提及的数组都只包含基本数据类型的元素,数组还可以包含对象,数组的方法和属性对对象依然适用。
创建JSON对象数组
- 将JSON数组分配给变量
var months = [{ 'id': 1, 'name': 'January' }, { 'id': 2, 'name': 'February' }];
console.log(JSON.stringify(months));
console.log(months)
2. 使用.push()运算符在对象数组中动态添加值来创建JSON对象数组
var monthNames = ['January', 'February'];
var month = {};
var monthsArray = [];
for (let i = 0; i < 2; i++) {
month.id = (i + 1);
month.name = monthNames[i];
monthsArray.push({ ...month });
}
console.log(JSON.stringify(monthsArray))
JSON.stringify() 函数将 JSON 数组转换为字符串格式 最后的运行结果和方法一的运行结果相同
- 使用循环在数组的索引处添加对象
// 创建一个空的 JSON 对象数组
var jsonArray = [];
// 使用 for 循环向数组中添加对象
for (var i = 0; i < 5; i++) {
var jsonObject = {
index: i,
data: "Data " + i
};
jsonArray[i] = jsonObject;
}
// 输出 JSON 对象数组
console.log(jsonArray);
在上面的代码中,我们首先创建了一个空的 JSON 对象数组 jsonArray。然后使用 for 循环,在每个索引处添加一个包含 index 和 data 属性的 JSON 对象。最后,我们打印出 JSON 对象数组
从JSON对象数组访问对象
var months = [{'id': 1, 'name': 'January'}, {'id': 2, 'name': 'February'}];
console.log(months[0].id);//1
console.log(months[0].name);//January
通过给数组对象的索引处复制来修改对象数组的元素
months[0].id = 3;
months[0].name = 'March';
console.log(months[0].id);//3
console.log(months[0].name);//March
迭代 JSON对象数组
for (let i = 0; i < months.length; i++) {
console.log(`${i} id:${months[i].id}, name:${months[i].name}`)
}
控制台输出结果如下 0 id:1, name:January 1 id:2, name:February
将对象添加到JSON对象数组
使用 .push() 函数将一个 JSON 对象添加到数组的末尾。.unshift() 函数在 JSON 数组的开头添加一个元素。.splice() 在数组中的指定索引处插入一个对象。
var months = [{'id': 1, 'name': 'January'}, {'id': 2, 'name': 'February'}];
months.push({'id': 4, 'name': 'April'});
console.log(JSON.stringify(months));
months.unshift({'id': 12, 'name': 'December'})
console.log(JSON.stringify(months));
months.splice(3, 0, {'id': 3, 'name': 'March'});
console.log(JSON.stringify(months));
从JSON对象数组中删除对象
可以使用 javascript 的 .pop() 方法从 JSON 对象数组的末尾删除元素。.shift() 从 JSON 对象数组的开头删除一个对象。.splice() 函数删除 JSON 数组指定索引处的元素
var months = [
{'id': 12, 'name': 'December'}, {'id': 1, 'name': 'January'},
{'id': 2, 'name': 'February'}, {'id': 3, 'name': 'March'},
{'id': 4, 'name': 'April'}
];
months.shift();
console.log(JSON.stringify(months));
months.pop();
console.log(JSON.stringify(months));
months.splice(1, 1);
console.log(JSON.stringify(months));
JSON对象数组中搜索元素
javascript 内置函数如 .filter()、.find()、findIndex() 可用于在 JSON 对象数组中搜索对象。 .filter() 函数返回一个包含满足特定条件的对象的数组, .find() 返回满足作为内联函数传递给它的条件的对象, .findIndex() 将返回如果可以在数组中找到对象的索引,则返回 -1。
var months = [
{'id': 12, 'name': 'December'}, {'id': 1, 'name': 'January'},
{'id': 2, 'name': 'February'}, {'id': 3, 'name': 'March'},
{'id': 4, 'name': 'April'}
];
(months.filter(i => i.name === 'April').length) ?
console.log('April month found') :
console.log('Not found');
(months.find(i => i.name === 'January') != {}) ?
console.log('January month found') :
console.log('Not found');
(months.findIndex(i => i.name === 'April') > -1) ?
console.log('April month found') :
console.log('Not found');
JavaScript处理对象数组常用的方法
前端在处理后端返回的数组对象格式的数据,对数据进行判断整合的常用方法
- Object.keys()取出对象所有属性名 返回数组
- Object.values()取出对象所有值 返回数组
- arr.reduce();数组求和 求乘积 很方便
- map()
data = [
{name: "n1", "phone": "15075245632"},
{name: "n2", "phone": "15532564789"},
{name: "n3", "phone": "1923652485"}
];
arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
})
var arr = [1, 2, 3, 4];
var sum = arr.reduce((x,y)=>x+y)
var mul = arr.reduce((x,y)=>x*y)
console.log( sum ); //求和,10
console.log( mul ); //求乘积,24
计算数组出现次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum = names.reduce((pre,cur)=>{ if(cur in pre){ pre[cur]++ }else{ pre[cur] = 1 } return pre },{}) console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
数组去重
let arr = [1,2,3,4,4,1]
let newArr = arr.reduce((pre,cur)=>{
if(!pre.includes(cur)){
return pre.concat(cur)
}else{
return pre
}
},[])
console.log(newArr);// [1, 2, 3, 4]
二维数组转化
let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = arr.reduce((pre,cur)=>{
return pre.concat(cur)
},[])
console.log(newArr); // [0, 1, 2, 3, 4, 5]
多维数组转化
let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
const newArr = function(arr){
return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[])
}
console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
对象数组求和
var result = [
{
subject: 'math',
score: 10
},
{
subject: 'chinese',
score: 20
},
{
subject: 'english',
score: 30
}
];
var sum = result.reduce(function(prev, cur) {
return cur.score + prev;
}, 0);
console.log(sum) //60
将对象数组映射出值
var users = [
{name: "张三", "email": "zhang@email.com"},
{name: "李四", "email": "li@email.com"},
{name: "王五", "email": "wang@email.com"}
];
var emails = users.map(function (user) { return user.email; });
console.log(emails.join(", ")); // zhang@email.com, li@email.com, wang@email.com
转载自:https://juejin.cn/post/7370925939318636596