第七天
数组
数组是引用数据类型中的对象数据类型(特殊对象)
创建一个数组,也要开辟一个堆内存,堆内存中存储数据对象中的键值对
- 数组中我么看到的每一项都是属性值,默认的属性名是数字,数字从零开始递增,数字代表当前是第几项,我们把代表位置的数字属性名称为“索引”,数组是以数字为索引,索引从零开始递增的结构!
- 默认存在一个length属性,代表数组的长度(有多少项)
- 数组中存在的每一项可以是任何数据类型
真实项目中,我们从服务器获取到的数据,一般都是对象或者数组(JSON格式),而且结构层级一般也都是多级结构,所以学会数组/对象的相关操作,能够根据需求把获取的数据进行有效的解析和处理,是当下前端开发中非常重要的知识点;尤其是vue/react开发的时候,我们都是在不断的操作数据,来控制视图的渲染,而操作的数据也是以对象和数组偏多;...
学习数组步骤
- 掌握基础操作
- 掌握数组中常用的内置方法 (浏览器天生给数据提供的方法)
- 掌握数组排序和去重(算法)
......
获取每一项的值
-
arr[索引] 或者对某一项进行操作
-
arr.length-1:最后一项索引
-
arr[arr.length] = x:向数组末尾追加一个新项
-
基于delete删除数组中的某一项(把它当作普通对象操作),键值对可以删掉,但是length并不会跟着改变,一般数组删除不用它!
-
基于arr.length--可以实现删除数组中最后一项
let arr = [10,20,30] arr[0] = 100; console.log(arr[arr.length - 1]); arr[3] = 40; delete arr[0]; arr.length--;
数组迭代(遍历数组中的每一项)
```
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
console.log(`当前遍历的是数组中索引为:${i},数值为:${item}的这一项!`);
}
```
作为普通对象,基于FOR IN遍历数组中所有的键值对
```
for (let attr in arr) {
console.log(attr, arr[attr]);
}
```
还可以基于 while循环、for of循环、内置的迭代方法来遍历数组每一项
数组中常用的内置方法
基于这些方法可以让我们有效的对数组进行操作 => console.dir(Array.proto)
let arr = [10, 20, 30];
-
关于数组的增删改
-
push
- @params:参数个数不固定,类型也不固定,都是向数组末尾依次追加的内容
- @return:[number]新增后数组的长度
- 原始数据改变
- 向数组末尾追加元素 => 基于键值对操作:arr[arr.length]=xxx
let result = arr.push(40, '珠峰培训'); console.log(result); //=>5
-
pop
- 删除数组最后一项
- @params:无
- @return:被删除的那一项内容
- 原始数组改变
let result = arr.pop();
arr.length-- 删除最后一项
+ shift
- 删除数组第一项
- @params:无
- @return:被删除的那一项内容
- 原始数组改变`let result = arr.shift();`
-
unshift
- 向数组开始位置新增内容
- @params:个数不定、类型不定,都是要依次新增的内容
- @return:[number]新增后数组的长度
- 原始数据改变
let result = arr.unshift(0, '珠峰培训');
-
splice
- 实现数组指定位置的增删改
- arr.splice(n,m):从数组索引n开始,删除m个元素,返回结果是以新数组的方式,把删除的内容进行存储(m不写就是删除到末尾)
- arr.splice(n,m,x):从索引n开始,删除m个元素,用x替换删除的内容,返回结果是一个数组,存储删除的内容
- arr.splice(n,0,x1,x2...):从索引n开始,一个都不删除(返回结果是空数组),把x1或者更多值“插入到索引n前面”
- 原始数组都会改变
let arr = [10, 20, 30, 40, 50, 60, 70]; ========新增(一个都不删) let result = arr.splice(2, 0, 100, 200, 300); console.log(result, arr); //=>result=[] arr=[10, 20,100,200,300 ,30, 40, 50, 60, 70] ========修改(删除掉一部分,然后用一些值替换即可) let result = arr.splice(2, 2, '珠峰培训', '周啸天'); console.log(result, arr); //=>result=[30,40] arr=[10, 20, '珠峰培训','周啸天', 50, 60, 70] ========删除 let result = arr.splice(2, 3); console.log(result, arr); //=>result=[30,40,50] arr=[10,20,60,70] let result = arr.splice(0); //=>从索引零开始,删除到末尾(清空原来数组,把原来数组中的每一项都存放到新数组RESULT中) console.log(result, arr); //=>result=[10, 20, 30, 40, 50, 60, 70] arr=[]
需求:删除数组末尾这一项,你有几种办法?
let arr = [10, 20, 30, 40, 50, 60, 70];
- arr.length--;
- arr.pop(); //=>返回结果70
- arr.splice(arr.length - 1); //=>从最后一项开始,删除到末尾(删除一个) 返回结果[70]
- delete arr[arr.length - 1]; //=>虽然可以删除,但是LENGTH长度不变(一般不用)
- ...
需求:向数组末尾追加‘珠峰’
let arr = [10, 20, 30, 40, 50, 60, 70];
- arr.push('珠峰');
- arr[arr.length] = '珠峰';
- arr.splice(arr.length, 0, '珠峰');
- 实现数组指定位置的增删改
-
-
关于数组查询和拼接
-
slice
- slice(n,m):实现数组的查询,从索引n开始,查找到索引m处(不包含m),把查找到的内容以新数组的方式返回,原始数组不变
- console.log(arr.slice(2)); //=>[30, 40, 50, 60, 70] 第二个参数不写是直接查找到数组末尾
- console.log(arr.slice(0)); //=>[10, 20, 30, 40, 50, 60, 70] 可以理解为把原始数组中的每一项都查找到,以新数组返回,实现出“数组的克隆”:得到的新数组和原始数组是两个不同的数组(两个不同的堆),但是堆中存储的内容是一致的
- slice(n,m):实现数组的查询,从索引n开始,查找到索引m处(不包含m),把查找到的内容以新数组的方式返回,原始数组不变
-
concat
- concat:实现数组拼接,把多个数组(或者多个值)最后拼接为一个数组,原始的数组都不会变,返回结果是拼接后的新数组
let arr1 = [10, 20, 30]; let arr2 = [50, 60, 70]; let arr = arr1.concat('珠峰', arr2); console.log(arr); //=>[10, 20, 30, "珠峰", 50, 60, 70]
-
-
转化为字符串
- toSting
- toString():把数组中的每一项按照“逗号分隔”,拼接成对应的字符串
- join
- join([char]):指定分隔符
- 原始数组都不会改变
console.log(arr.toString()); //=>'10,20,30,40,50,60,70' console.log(arr.join()); //=>等价于toString console.log(arr.join('+')); //=>'10+20+30+40+50+60+70' 如果这个字符串能够变为JS表达式执行,则代表数组中每一项的求和 =>eval let str = arr.join('+'); let total = eval(str); console.log(total); let total = 0; for (let i = 0; i < arr.length; i++) { total += arr[i]; } console.log(total);
- toSting
-
验证是否包含某一项的
- indexOf / lastIndexOf
- 获取数组中指定项的索引
- indexOf([item]):获取当前项在数组中第一次出现位置的索引
- lastIndexOf([item]):获取当前项最后一次出现的索引
- 如果数组中不包含这一项,则返回结果是-1
- 获取数组中指定项的索引
- includes
- 验证数组中是否包含这一项,包含返回true,不包含返回false
- indexOf / lastIndexOf
-
关于排序的
- reverse
- 把原始数组倒过来排列,返回的结果是排列后的原始数组
- sort
- 把原始数组按照规则进行排序,原始数组会改变(返回结果也是改变后的原始数组)
- sort排序,默认不是按照每一项的数值大小排序,而是按照每一项的每一个字符编码来进行排序的,所以直接写sort,不能处理两位及两位以上的内容排序
- reverse
-
关于数组迭代的方法(数组中常用的迭代方法)
- forEach
- forEach([函数]):遍历数组中的每一项(数组中有多少项,函数都会相继被执行多少次),
- item:当前遍历的这一项内容
- index:当前项的索引
- map
- forEach是不支持返回值的,而map可以在forEach的基础上支持返回值,把原来数组中每一项的值
- item:当前循环这一次的值
- 当前值对应的索引
- 函数中返回啥,都是把数组中当前项替换成啥
- 以后会涉及的:find / filter / every / some / reduce ...
- forEach
- 记忆的方式
- 方法的意义和作用
- 参数(执行方法的时候传递的内容)
- 返回值(执行完方法返回的结果)
- 原始数组是否改变
数组去重的方式(12种)
数组去重就是去掉数组中的重复项
- 双for循环
- 对象的键值对方式
方案一:
依次遍历数组中的每一项,拿当前项和其“后面”的每一项进行比较,如果后面还有和它相同的,则说明这是重复的,我们把后面中重复的这一项删除掉即可
======================外层循环控制每一次拿出一项和其后面的比
方案二:对象键值对的方式
我们把item作为obj对象的属性名和属性值分别存储进去(每一次存储之前)
// i < arr.length - 1 最后一项不需要再拿出来了,因为每一次都是和当前项后面的比较,而最后一项后面没有任何的东西,所以也就没有必要再拿出来比较了
for (let i = 0; i < arr.length - 1; i++) {
// 每一次拿出来要和后面依次比较的那一项
let item = arr[i];
//======里层循环控制和当前项后面的每一项逐一比较
// let j = i + 1 从当前项的后一项开始逐一比较即可
for (let j = i + 1; j < arr.length; j++) {
if (item === arr[j]) {
// 当前项和后面中的某一项相等了,此时我们把后面中的这一项从原始数组中删除掉
arr.splice(j, 1);
j--; //=>删除完,先让j--,然后在j++,相当于没加没减,下一轮还是从当前索引开始比较,这样防止数组塌陷带来的问题
}
}
}
```
for (let i = 0; i < arr.length - 1; i++) {
let item = arr[i];
for (let j = i + 1; j < arr.length; j++) {
if (item === arr[j]) {
// 用最后一项替换当前项
arr[j] = arr[arr.length - 1];
// 最后一项删掉
arr.length--;
// 下一轮还和这一项比(因为这一项已经变为最新的最后一项了)
j--;
}
}
}
console.log(arr);
```
let arr = [1, 2, 3, 1, 1, 4, 2, 3];
for (let i = 0; i < arr.length - 1; i++) {
let item = arr[i];
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] === item) {
// 后面某项值和当前项相等了:直接删除
/* arr.splice(j, 1);
j--; */
// 原始数组中的顺序会变化,但是不会导致索引前置这种情况(性能好)
arr[j] = arr[arr.length - 1];
arr.length--;
j--;
}
}
}
console.log(arr);
- 只有一个循环,所以性能很好
- 如果数组中出现对象则存在问题(因为对象的属性名不能是对象,遇到会转换为字符串);如果数组中存在数字10和字符串'10',则也会认为是重复的(对象中的属性名是数字和字符串没啥区别);数组中的值如果是undefined可能也会出现问题
let arr = [1, 2, 3, 1, 1, 4, 2, 3];
let obj = {};
for (let i = 0; i < arr.length; i++) {
// 把每一次循环得到的当前项,作为对象的属性名和属性值存储进去
let item = arr[i];
if (obj[item] !== undefined) {
// 证明对象中有这个属性(也就是之前存储过,数组中之前就有这个值),当前值是重复的,我们需要把当前这项的值删掉即可
arr[i] = arr[arr.length - 1];
arr.length--;
i--;
continue;
}
obj[item] = item;
}
console.log(arr);
方案三:
ES6中没有提供现成的去重办法,但是提供了一些去重的方式 :Set数据结构
let obj = {
y: 200
};
let arr = [obj, 1, 2, 3, 1, obj, 1, 4, 2, 3, '3', {
x: 100
}, {
x: 100
}];
arr = Array.from(new Set(arr));
console.log(arr);