JavaScript的数组与数组方法

142 阅读9分钟

数组

基本类型的变量只能存储一个值,数组可以存储多个值。

数组最大的用处就是可以进行批量操作。

基本概念

  • 数组,可以存储多个值,每一项都可以保存任何类型的数据,尽量要确保数组中存储的数据类型是相同的,是有序的数据集合。
  • 下标(索引、键、key),索引的值从0开始。
  • 下标和值对应的一组数据称为元素。

数组创建

  • 使用Array创建,var arr = new Array();

    var arr = new Array('red','green','blue');
    console.log(arr);
    

    如果Array()中如果只有一个元素 并且这个元素是数值,将会定义为数组的长度。

    var arr= new Array(10);
    console.log(arr);//[empty × 10] length=10
    

    声明数组的时候也可以省略new 操作符,和new Array()使用方式是相同的。

  • 使用数组字面量方法来创建(常用)

    数组字面量由一堆包含数组项的方括号表示,多个数组项之间使用逗号分隔。

    var arr=['red','green','blue'];
    console.log(arr);
    

数组元素的个数

数组中元素的个数保存在数组的length属性中,这个属性的值始终大于等于0。

数组的最后一项的下标(索引)为length-1

数组的操作

  • 向数组中添加元素,语法:数组[索引] = 元素

  • 读取数组中的元素,语法:数组[索引]。如果读取的是一个不存在的元素,回返回undefined。

  • 修改数组中的元素,覆盖。

  • 删除数组中的元素,数组的length属性是可以修改的,将length设置的比原来的length小就会将后面的删除。

  • 清空数组,length=0arr=[]

数组的遍历

常见使用for循环,for(i = 0;i <= arr.lenght-1;i++)

还可以使用 for-of语句。语法:

​ for(变量 of 可迭代的对象){ 语句 ​ } ​ for-of的循环体会执行多次,数组中有几个元素就会执行几次

const arr = ['red','green','blue'];
for(let value of arr){
    console.log(value);
}

数组的方法

非破坏性方法

不会影响原数组,而是返回一个新的数组

  • Array.isArray(value) ,确定value是否是数组,如果是数组返回true否则返回false

这个属性是Array的对象属性,不是存在Array.prototype中的,只能Array.isArray()这样使用

  • Array.prototype.concat(val1,val2,...) 基于当前数组中的所有项创建一个新数组,

​ 相当于先创建当前数组的一个副本,然后将收到的参数添加到这个副本的末尾。

​ 最后返回新构建的数组

// - 没有给concat传递参数,这个时候只是复制当前数组。
var a = [];
var b = a.concat();
console.log(b)
console.log(a == b)//false ,地址不同

// - 如果给concat传递的是一个或多个项,将传递的参数添加到结果的数组中
var a = [];
console.log(a.concat([1, 2, 3]))//[1,2,3] 会将数组展开后逐个元素插入
console.log(a.concat([4, 5, 6], 7))//[4,5,6,7]
console.log(a.concat([1, 2, 3, [4, 5, 6]])) //[1,2,3,Array(3] 只会展开一层
  • Array.prototype.join(),使用指定的字符串拼接数组中的每个元素,组成一个字符串

    String.split(),与这个为互逆操作,将字符串根据指定字符拆分,返回一个新数组

var colors = ['red', 'green', 'blue', 'yellow']
var res = colors.join('😊')
console.log(res)
var newColors = res.split('😊')
console.log(newColors)
  • Array.prototype.slice(),复制当前数组中的一个或多项创建要给新数组

  • 只有一个参数,返回的是从指定位置开始到当前下标到数组末尾的所有项

  • 如果有两个参数,返回起始项目和结束项目之间的项,包含起始不包含结束

  • 一个参数都不写的情况,从0开始一直到最后

  • 索引可以为负值(从后往前数)

  • 如果将两个参数全部省略,则可以对数组进行浅拷贝。

// 一个参数
var colors = ['red','green','blue','yellow']
console.log(colors.slice(2)) //['blue','yellow']
// console.log(colors) //原数组不变
//两个参数
console.log(colors.slice(1,3)) //[green,blue]
// console.log(colors) //原数组不变
//0个参数
console.log(colors.slice()) //与原数组相同 但地址不同
  • Array.prototype.toString(),返回数组的字符串表示
var  colors = ['red','green','blue']
console.log(colors.toString()) //转换为字符串,里面的项用逗号拼接,然后去掉两边的中括号
  • Array.prototype.indexOf(),查找指定的值并返回要查找的项在数组中的位置。

    没有找到返回-1, 比较使用的是全等操作符

var colors = ['red','green','blue',1]
console.log(colors.indexOf('green'))//1
console.log(colors.indexOf('blue'))//2
console.log(colors.indexOf('1'))//-1 全等比较 1==='1'为false
console.log(colors.indexOf('green',2))//-1 第二个参数指定了查找的其实位置,不写默认从0开始
  • lastIndexOf()

    获取元素在数组中最后一次出现的位置。

    找到了返回元素的索引,没找到返回-1

破坏性方法:

  • Array.prototype.push(),接受任意数量的参数,逐个添加到数组末尾

返回修改后的数组长度

var colors = ['red', 'blue', 'green']
console.log(colors.push('yellow', 'black', 'white'))//6
console.log(colors, colors.length)
  • Array.prototype.pop(),从数组末尾移除最后一项,减少数组的length值

    返回被移除的项

    var colors = ['red', 'green', 'blue']
    console.log(colors.pop())  //blue
    console.log(colors, colors.length)
    
  • Array.prototype.unshift(),在数组前端添加任意个数元素

    返回新数组的长度

    var colors = ['red', 'green', 'blue']
    console.log(colors.unshift('yellow', 'black', 'white')) //6
    console.log(colors, colors.length)
    
  • Array.prototype.shift(),移除数组中的第一个项,并将数组长度减1

返回被移除的项

var colors = ['red', 'green', 'blue']
console.log(colors.shift()) //red
console.log(colors, colors.length)
  • Array.prototype.splice(),向数组的中部插入项,可以实现 删除 替换 插入

    格式str.splice(startIndex,length,item1,item2.....)

    // 删除,可以删除任意数量的项,只要指定前两个参数,即删除的第一项的位置和要删除的项目数量
    // 返回被删除的项组成的数组
    var colors = ['red','green','blue','yellow']
    //从下标0开始,删除2个项目
    console.log(colors.splice(0,2))//['red','green']
    console.log(colors,colors.length)
    
    //替换 可以向指定的位置插入任意数量的项,且同时删除任意数量的项,需要指定三个参数,起始位置 删除的项数量,要插入的项
    //返回被删除的项组成的数组,删除与插入的下数量不需要相等
    var colors =['red','green','blue']
    //从下标1开始,删除1个项目,并在下标1的位置开始逐个插入新元素
    console.log(colors.splice(1,1,'black','white')) //['green']
    console.log(colors,colors.length)
    
    //插入 可以向指定位置插入任意数量的项
    // 三个参数:起始位置,0(删除的项目数量为0),要插入的项
    var colors = ['red','green','blue']
    console.log(colors.splice(1,0,'black','white'));//返回删除的项组成的数组 即空数组
    console.log(colors,colors.length)
    
  • Array.prototype.reverse(),反转数组项的顺序

    返回反转后的原数组。

var colors = ['red','green','blue']
console.log(colors.reverse()) //['blue','green','red']
console.log(colors,colors.length)
  • Array.prototype.sort([sortFunction]),按升序排列数组项,(最小的值位于最前面,最大的值排在最后面)。排序后改变原数组

    • 不传递参数的情况,sort方法会调用每个数组项的toString(),然后比较得到的字符串,

      即便都是数值number使用sort()方法比较的也是字符串,比较ASCLL编码。

    • sort可以接受一个比较函数作为参数,作为参数的函数需要两个参数, 如果第一个参数要放在第二个参数前面就返回负数,相等就返回0,第一个参数放在第二个参数后面就返回正数

    var numArr = [12,3,44,51,2,-2,11,6]
    console.log(numArr.sort());//把数值当作字符串比较
    console.log(numArr.sort(function(a,b){//升序排序
        return a-b; //a大于b时为正值,则a放在b的后面。 a小于b时为负值,则a放在b前面。
    }))
    console.log(numArr.sort(function(a,b){
        return b-a; //a大于b时为负值,则a放在b的前面。 a小于b时为正值,则a放在b的后面
    }))
    

数组常见的遍历方法

  • Array.prototype.forEach(),对数组中的每一项执行指定函数

没有返回值(返回值是undefined)

var colors = ['red', 'green', 'blue', 'yellow']
colors.forEach(function (val, index) {
    console.log(val, index);
})
  • Array.prototype.map(),对数组中的每一项执行指定函数

    返回每次函数调用的结果组成的数组(即返回什么就是什么)

    var colors = ['red', 'green', 'blue', 'yellow']
    var res = colors.map(function (val, index) {
        return val + '----😊----' + index
    })
    console.log(res)
    
  • Array.prototype.filter(),对数组中的每一项执行给定函数

    filter方法会得到 该函数返回值为true的项目 所组成的数组

    var colors = ['red', 'green', true, 'blue', 123]
    var res = colors.filter(function (val, index) {
        if (typeof val == 'string') {
            return true
        } else {
            return false
        }
    })
    console.log(res)//['red', 'green', 'blue']
    
  • Array.prototype.every(),对数组中的每一项执行给定函数

如果该函数中每一项都返回true,则返回true

var colors = ['red', 'green', 'blue', 'yellow',1]
var res = colors.every(function (val, index) {
    if (typeof val == 'string') {
        return true
    } else {
        return false
    }
})
console.log(res)//false
  • Array.prototype.some(),对数组中的每一项执行给定函数

    如果函数中至少有一个返回true,则返回true

    var colors = ['red', 'green', 'blue', 'yellow', 1]
    // var colors = [1,2,3,4,5] //false
    var res = colors.some(function (val, index) {
        if (typeof val == 'string') {
            return true
        } else {
            return false
        }
    })
    console.log(res) //true
    

ES6方法

  • Array.from() 用于将类数组对象转换为真正的数组:类数组对象(有length属性,有索引元素)和可遍历对象
var arrLike = { 0: 'red', 1: 'green', 2: 'blue', length: 3 }
var arr = Array.from(arrLike);
console.log(arrLike)
console.log(arr)
  • Array.of()将一组值转换为数组,返回新数组

    主要是为了解决ES5中使用构造函数创建数组时值只传一个元素会被默认为length的问题

    var arr1 = new Array(4)
    console.log(arr1, arr1.length) //[empty*4] length=4
    
    var arr2 = Array.of(4);
    console.log(arr2,arr2.length) //[4] length=1
    
  • Array.prototype.includes()方法返回一个布尔值,表示某个数组是否包含给定的值

    能找到则返回true,找不到则返回false

    主要解决的是indexOf是全等操作,不能查找NaN,但是includes可以查找NaN

    var arr=[1,2,NaN,11,55]
    console.log(arr.indexOf(2)) //1
    console.log(arr.indexOf('2')) //-1 全等操作 2==='2'为false
    console.log(arr.indexOf(NaN)) //-1 因为进行全等操作无法匹配NaN
    
    console.log(arr.includes(2)) //true
    console.log(arr.includes('2')) //false
    console.log(arr.includes(NaN)) //true
    

数组对象的复制

看是否是复制,主要看是不是产生了新的对象。

只是普通的等号并不是复制

// 不是复制的
const arr2 = arr;   //并没有产生一个新的对象,而是将两个数组指向了同一个内存地址
arr2[0] = '红色';   //改变arr2也会改变arr的内容 

slice()会产生一个新的数组对象,从而完成去数组的复制

const arr3 = arr.slice();
arr3[0] = '红色'; //改变arr3并不会改变arr的内容

深拷贝与浅拷贝

  • 浅拷贝(shallow copy)

    • 通常对对象的拷贝都是浅拷贝,只是简单的复制一层

    • 如果对象中存储的数据都是原始值字面量,则深浅拷贝没什么区别

    • 浅拷贝只会对对象本身进行复制,不会复制对象中的属性(或元素)

      const arr = [{ color: 'red' }, { color: 'green' }];
      const arr2 = arr.slice();//浅拷贝
      
      console.log(arr === arr2);//false
      console.log(arr[0] === arr2[0]); //true
      
  • 深拷贝(deep copy)

    • 深拷贝指不仅复制对象本身,还复制对象中的属性和元素(即嵌套多层拷贝)

    • 因为性能问题,通常情况不太使用深拷贝

      const arr3 = structuredClone(arr);//深拷贝
      
      console.log(arr === arr3);//false
      console.log(arr[0] === arr3[0]); //false
      
  • 展开运算符实现浅拷贝,...arr,可以将一个数组中的元素展开到另一个数组中或者作为函数的参数传递。

    const arr  = ['red','green','blue'];
    
    // const arr2 = [arr[0],arr[1],arr[2]];
    // const arr2 = [...arr];//与上一行等价
    const arr2 = ['black',...arr,'pink'];