持续输出JS第10篇-(JS数组)

490 阅读10分钟

前言

数组是引用数据类型中的对象数据类型(特殊对象)

创建一个数组,也是要开辟一个堆内存,堆内存中存储数组对象中的键值对

0:10

1:20

2:30

length : 3

1)数组中我们看到的每一项都是属性值,默认的属性名是数字,数字从零开始递增,数字代表当前是第几项,我们把代表位置的数字属性名称为“索引”;数组是以数字为索引,索引从零开始递增的结构!

2)默认存在一个length属性, 代表数组的长度(有多少项)

3)数組中存在的每一项可以是任何数据类型,真实项目中,我们从服务器获取到的数据,-般都是对象或者数組(JSON格式),而且结构层级一般也都是多级结构,所以学会数组/对象的相关操作,能够根据需求把获取的数据进行有效的解析和处理,是当下前端开发中非常重要的知识点;尤其是vue/react开 发的时候,我们都是在不断的操作数据,来控制视图的渲染,而操作的数据也是以对象和数組偏多; ...

 ==== 一维数组(只有- -级结构)
let arr = [102030];
let arr = [10'AA', true, null, undefined, Symbo1(1)];
====二维数组(多維数组) 有两级或者多级结构
letarr=[{
x: 100
},{
y: 200 .
}]; 

学习数组

  • 掌握基础操作
  • 掌握数组中常用的内置方法(浏览器天生给数组提供的方法)
  • 掌握数组排序和去查(算法)

遍历数组

数组迭代(遍历数组中的每一项)

for (let i = 0; i < arr.length; i++) {
let item = arr[i];
console. log(当前遍历的是数组中索引为: ${i}, 数值为: ${item}的这一 项!);
}

作为普通对象,基于FOR IN遍历数组中所有的键值对

for (let key in arr) {
console.1og(key, arr[key]);
}

还可以基于while循环、for of循环、内置的迭代方法来遍历数组每一项

数组常用内置方法

1.关于数组的增删改
+ push .
+pop
+ shift
+ unshift
+ splice
2.关于数组查询和拼接
+ slice
+ concat
3.转换为字符串
+ toString
+ join
4.验证是否包含某一项的
+ indexOf / lastIndex
+ includes
5.关于排序的
+ reverse
+ sort
6.关于数组迭代的方法
+forEach
+map

记忆的方式

1.方法的意义和作用

2.参数(执行方法的时候传递的内容)

3.返回值(执行完方法返回的结果)

4.原始数组是否改变

数组增删改的五个方法

let arr=[10,20,30]

1

push: 向数组末尾追加元素事
@params:
参数个数不固定,类型也不固定,都是向数组末尾依次追加的内容
@return:
[NUMBER ]新增后数组的长度
原始数据改变
基于对象键值对操作: arr[arr. length]=xxx

let result = arr. push(40'呵呵');
console. log(result); //=>5

2

pop:
删除数组最后一项
@params:无
@return:
被删除的那一项内容
原始数组改变
arr.length--
删除最后一项

let result = arr.pop();
console.1og(result,arr);

3

unshift: 向数组开始位置新增内容

@params:

个数不定、类型不定,都是要依次新增的内容

@return:

[NUMBER ]新增后数组的长度

原始数据改变

let result = arr. unshift(0, '呵呵');

和push差不多,不过是在开头加

4


shift: 删除数组第一项

@params:无
@return:
被删除的那一项内容

原始数组改变

let result = arr. shift();
console.1og(result, arr);

5

splice:实现数组的增删改

arr.splice(n,m);从数組索引n开始,删除m个元素,

返回结果是以新数組的方式,把删除的内容进行存储,如果没有m那就是删到尾

原始数組都会改变

let arr = [10203040506070];
let result = arr.splice(2, 3);
console.1og(result, arr); //=>result=[30,40,50] arr=[10,20, 60,70]

清空数组操作

let result = arr. splice(0); 
//=>从索引零开始, 删除到末尾(清空原来数组, 把原来数组中的
每一项都存放到新数组RESULT中 )
console. log(result,arr); 
//=>resu1t=[10, 20, 30, 40, 50, 60, 70] arr=[]

从哪里开始删多少个元素,再在它前面加上哪些元素

let arr = [10203040506070];
let result = arr.splice(2, 0100200300);
console.1og(result, arr);

需求:删除数组末尾这一项,你有几种办法
let arr = [10, 203040506070];
arr. length--; .
arr.pop(); //=>返回结果70
arr.splice(arr. length - 1); 
//=>从最后一 项开始,删除到末尾(删除-个)返回结果[70]
delete arr[arr.length - 1];
//切记不能换成length-- 
//=>虽然可以删除,但是LENGTH长度不变(一般不用)
// ...

最后一个方法的结果,LENGTH长度不变

需求;向数组末尾追加‘呵呵’
let arr = [1020304050, 6070];
arr. push('呵呵');
arr[arr.length] = '呵呵';
arr.splice(arr.length-1, 0,'呵呵');
//这个会加在倒数第二的位置上
arr.splice(arr.length, 0,'呵呵');

数组查询和拼接

slice(n,m):实现数组的查询,从索引n开始,查找到索引为m处(不包含m),把查找到的内容以新数组的方式返回,原始数组不变

let arr = [10, 2030, 40506070];
let result = arr.slice(2, 5);
console. log(result, arr); 
//=>resu1t=[30, 4050] arr=[10, 20304050, 60,70]
console. log(arr.slice(2)); 
//=>[30, 40, 50, 60, 70]第二个参数不写是直接查找到数组末尾
console. log(arr.slice(0)); 
//=>[10, 20, 30, 40, 50, 60, 70]

可以理解为把原始数组中的每一项都查找到,以新数组返回,实现出“数组的克隆”:得到的新数组和原始数组是两个不同的数组(两个不同的堆),但是堆中存储的内容是-致的,这是浅克隆

concat: 实现数组拼接,把多个数组(或者多个值)最后拼接为一个数组,原始的数组都不会变,返回结果是拼接后的新数组

let arr1 = [10, 20, 30];
let arr2 = [50, 6070];
let arr = arr1.concat('呵呵', arr2);
console.log(arr); //=>[10, 20, 30,"呵呵", 50, 60, 70]

转换为字符串

let arr = [10,20,30, 40,50, 60, 70];

把数组转化为字符串:

  1. toString(); 把数组中的每一项按照“逗号分隔”, 拼接成对应的字符串

  2. 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('+');//JS表达式
let total = eval(str);
console.log(total);

原来要搞循环才能实现的求和,现在用个total就能搞定。

验证是否包含某一项

获取数组中指定项的索引

indexOf([item]):获取当前项在数组中第一次出现位 置的索引

lastIndex0f([item]) :获取当前项在数组中最后一次出现位置的索引

let arr = [10, 20, 30, 10, 20, 10, 30];
console. log( arr. index0f(20)); //=>1
console. log(arr . lastIndex0f(20)); //=>4
console. log(arr . index0f(40)); //=>-1 如果数组中不包含这一 项,则返回结果是-1
// =>基于这个特征来验证数组中是否包含某一项
if (arr. index0f(40) > -1) {
//数组中包含这一项
}

第二种方法

includes:验证数组中是否包含这一项,返回TRUE/FALSE

console. log(arr . includes(40));

关于排序

reverse: 把原始数组倒过来排列,返回的结果是排列后的原始数组,原始数组改变

letarr=[4,3,2,5,1];
let result = arr.reverse();
console.log(result, arr);|

不是一个新数组,是改变后的原始数组,同一个堆内存,没有开辟新的堆

sort;把原始数组按照规则进行排序,原始数組会改变(返回结果也是改变后的原始数组)SORT支持传递回调函数,基于自定义的排序规则,进行排序的

arr.sort(); //=>默认按照由小到大排序
console.1og(arr); //=>[1,2,3,4,5]
let arr = [12, 23, 110, 34, 2, 4, 9];


arr.sort(); //=>S0RT排序,默认不就是按照每一项的数值大小排序, 而是按照每一项的每一个字符编
码来进行比较排序的,所以导致直接写SORT,不能处理两位及两位以上的内容排序
console.1og(arr); //=>[110, 12, 2, 23, 34, 4, 9]

按照字符编码来排的

那要怎样实现多位数的排序呢?

let arr = [12, 23, 110, 34, 2, 4, 9];
arr . sort(function (a, b) {
// => RETURN A-B升序,B-A降序
return b - a;
});
console.1og(arr); 

打印

[2, 4,9, 12,23, 34, 110]

数组迭代的方法

数组中常用的迭代方法(遍历数组中每-项的)

forEach([函数]):遍历数组中的每一项(数组中有多少项,函数会相继被执行多少次),每一次执行函数,都可以在函数中获取到当前遍历的这一项和对应的索引

其他迭代方法: find filter every some reduce ...

let arr =[10,20,30,40,50];

arr.forEach(function () {
    console.log('ok');
})

输出5次OK,说明循环5次

arr.forEach(function (item, index){
    //此函数会被循环执行五次(数组中有5项)
    // item: 当前遍历这一项的内容
    // index: 当前项的索引
console. log(item, index);
}); 

解决了格式问题和循环问题

数组就和的方式console. log(eval(arr . join('+')));如果数组 中出现非有效数字,则最后结果是NaN

let total = 0;
arr. forEach(function (item, index) {
item = Number(item);
if (isNaN(item) === false) {
total += item;
   }
});
console. log(total);

map: forEach是不支持返回值的,而map可以在forEach的基础上支持返回值

MAP支持返回值,但是不会改变原来的数組,执行完的返回结果是修改后的新数组

let arr = [1020304050];
let result = arr .map(function (item, index){
    //数组中有5项,此函数被循环执行了5次
    // item: 当前循环这- -次的值
    // index; 当前值对应的索引
    //函数中返回啥,都是把数组中当前项替换成啥
    return '@@' ;
});
console.log(result); 

return 'item*10' ;

数组去重的12种方式

双for循环(最稳)

方案1:依次遍历数组中的每一项,拿当前项和其“后面”的每一 项进行比较,如果还有面中有和他相同的,则说明这是这是重复的,我们把后面中重复的这一项删除掉即可。

外层循环控制每一次拿出一项和其后面的比 i < arr.length-1最后-项不需要再拿出来了,因为每一次都是和当前项后面的比较,而最后一项后面没有任何的东西,所以也就没有必要再拿出来比较了

let arr =[1,2,3,2,3,4,5,2,3,4,2,1,3,2,4];

for(leti=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);
     }
}
console. log(arr);

但是!!!

为什么呢?

arr.splice0删除的时候,会存在的问题

1.数组塌陷问题

2.性能有所影响( 如果删除的这一项后面还有1000万项,那么这1000万项的索引都要向前提一位)在原始的数组中, 一旦基于splice删除某一项 ,那么其后面所有项的索引都要向前提一位

解决

为了防止数组塌陷导致的循环跳过某-项,我们在删除完成后,循环的索引不能累加1 ,还应该从当前索引在循环-次(因为当前这一项的值,已经变为一个新的值了)

法1 添加j--;

for(letj=i+1;j<arr.length;j++){
if (item === arr[j]) {
      arr.splice(j, 1);
      j--; //=> 先让j--,然后在j++,相当于没加没减,下一轮还是从当前索引开始比较,这样防止数组塌陷带来的问题
         }
    }
}
console.1og(arr); .

法2 用最后一项替换当前项

 for(leti=0;i<arr.length-1;i++){
     let item = arr[i];
     for(letj=i+1;j<arr.length;j++){
        if (item === arr[j]) {
                //用最后一项替换当前项
            arr[j] = arr[arr.1ength-1];
                //最后一项删掉
            arr.length--;
    //下一轮还和这一项比(因为这一项已经变为最新的最后一项了)
            j--;
        }
    }
}
console.log(arr);

对象键值对方式

方案二:对象键值对的方式

1.只有一个循环,所以性能很好

2.如果数组中出现对象则存在问题(因为对象的属性名不能是对象,遇到会转换为字符串) ;

3.如果数组中存在数字10和字符串'10',则也会认为是重复的(对象中的属性名是数字和字符串没啥区别) ; 数组中的值如果是undefined可能也会出现问题....

letarr=[1,2,3,1,1,4,2,3];
let obj = {};
for (let i = θ; i < arr.length; i++) {
   //把每一次循环得到的当前项,作为对象的属性名和属性值存储进去
   let item = arr[i];
   if (obj[item] !== undefined) {
      // 证明对象中有这个属性(也就是之前存储过,数组中之前就有这个值),当前值是重复的,我们需要把当前这项的值删掉即可
       arr[i] = arr[arr.1ength - 1];
       arr.length--; .
       i--;
       continue;
    }
    obj[item] = item;
}
console. log(arr);

ES6中的set

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);|

OK,that is all!!