ECMAScript 中的Array类型

695 阅读10分钟

前言

Array类型是除了Object类型之外又是一个特别经常用的一个类型了,当然数组在其他的语言中都是不可缺少的属性,我们都知道不管js还是其他类的语言的数组都是数据的有序列表,但是在javaScript中的数组是有一定的区别的,具体的区别就是:js中的数组保存的数据可以是任何类型的数据,比如,我可以在第一个位置来保存数字,第二个位置保存字符串,第三和第四保存一个对象都完全OK,同时我还可以非常方便的操作数组的大小,添加新数据长度也会自动增长,动态调整什么的都是没有任何问题滴!而c或者其他的语言的数组和js的数组一对比就完全看出区别了,至于什么是数组,怎么创建、怎么用的等等基础用法这个就不用说了俺也默认你都知道的!

正文

我们日常对数据的各种操作都离不开数组,可以说数组的使用之多,接口返回的数据等等大都是使用到了数组

一、检测数组

对于数组我们已经知道了什么是数组了,那么检测数组又是怎么检测的呢?

其实检测数组的两个方法:

01、instanceof

let arr = []

console.log( arr instanceof Array)//true

instanceof的判断其实就是判断俩个操作数的构造函数的prototype属性,在一个全局执行环境下instanceof这个当然可以判断数组的类型,那假如一个网页同时有俩个框架下的情况下呢,我从一个框架传一个数组到另一个框架中,而我从一个框架传入的数组和这个框架中的数组却是存在不一样的构造函数,使用instanceof判断是否为数组的时候就会出现问题,那又该怎么办呢?

02、Array.isArray

可以说Array.isArray()方法就是为了针对这个问题而新增的,这个方法不管你从哪里来到哪里去,只要判断你是不是一个Array类型,看粟子:

let arr = [];

console.log(Array.isArray(arr))//true

二、数组方法

当数组存有了我们需要的数据,然后就是对数据进行各种各样的操作,而数组为我们提供了以下的方法(常用)

01、Array.prototype.join()

join()方法将数组(类数组对象)的所以元素都连接成一个字符串然后返回这个字符串,一个元素的情况下直接返回

粟子:

let arr = ['apple','tomatoes','banana']

console.log(arr.join())//apple,tomatoes,banana

console.log(arr.join('.'))//apple.tomatoes.banana

console.log(arr.join('-'))//apple-tomatoes-banana

let arr1 = ['apple']

console.log(arr1.join('+'))//apple

从例子可以看出,当什么都不添加的情况下的时候直接返回所有元素的字符串,添加分割符的情况时候就为元素直接添加一个新添加的字符,当数组只有一个元素的时候,无论添加什么都是直接返回该元素。

02、Array.prototype.push()

push()方法用于将一个或者多个元素添加到数组的末端,返回数组的新的长度

又一个粟子:

let arr = ['apple','tomatoes','banana']

console.log(arr.push('orange'))//4

console.log(arr.push('pear','peach'))//6

console.log(arr);//[ 'apple', 'tomatoes', 'banana', 'orange', 'pear', 'peach' ]

03、Array.prototype.pop()

pop()方法将数组的最后一个元素进行删除,然后会返回删除的改元素。该方法会改变数组的长度,空数组的情况下会返回undefined

对方表示不想说话并扔了一个粟子:

let arr = [ 'apple', 'tomatoes', 'banana', 'orange', 'pear' ]

console.log(arr.pop())//pear

console.log(arr.pop())//orange

console.log(arr)//[ 'apple', 'tomatoes', 'banana' ]

04、Array.prototype.concat()

concat方法是合并两个或者多个数组,然后返回一个合并的新数组,但是并不改变原来的数组

接到新的粟子:

let arr = [ 'apple', 'tomatoes' ]
let arr1 = ['banana', 'orange', 'pear']
console.log(arr.concat(arr1));//[ 'apple', 'tomatoes', 'banana', 'orange', 'pear' ]

console.log(arr.concat(2,arr1));//[ 'apple', 'tomatoes', 2, 'banana', 'orange', 'pear' ]

console.log(arr);//[ 'apple', 'tomatoes' ](原数组)

05、Array.prototype.sort()

sort方法对数组进行排序,返回排序的数组

一个简单的粟子:

let array = [1,3,2,4,5,7,6,8]

console.log(array.sort())//[ 1, 2, 3, 4, 5, 6, 7, 8 ]

拓展的粟子:

let array = [
  { id: 5, name: "jk" },
  { id: 2, name: "jc" },
  { id: 3, name: "jg" },
  { id: 4, name: "jp" },
  { id: 1, name: "jq" },
  { id: 6, name: "jr" }
]

console.log(array.sort( (a, b) => a.id - b.id)) //[ { id: 1, name: 'jq' },{ id: 2, name: 'jc' },{ id: 3, name: 'jg' },{ id: 4, name: 'jp' },{ id: 5, name: 'jk' },{ id: 6, name: 'jr' } ]

结果不出意外也是正序排序,降序反过来就ok了

06、Array.prototype.slice()

slice()方法从数组中返回选中的元素,对原数组进行浅拷贝

第一个参数为从0开始

第二个参数为从0开始

粟子:

let array = [
  { id: 5, name: "jk" },
  { id: 2, name: "jc" },
  { id: 3, name: "jg" },
  { id: 4, name: "jp" },
  { id: 1, name: "jq" },
  { id: 6, name: "jr" }
]

console.log(array.slice(0, 3)) //[ { id: 5, name: 'jk' },{ id: 2, name: 'jc' },{ id: 3, name: 'jg' } ]


//字符串

let str = 'this1 is slice'
console.log(str.slice(0,5))//this1

截取元素用的,但是原数组不会改变!

07、Array.prototype.splice()

splice()方法用于添加、移除、删除数组的元素,修改后的元素以数组形式返回。

第一个参数为修改开始的位置

第二个参数为删除的个数

第三个参数为插入的参数

粟子:

let array = [
  { id: 5, name: "jk" },
  { id: 2, name: "jc" },
  { id: 3, name: "jg" },
  { id: 4, name: "jp" },
  { id: 1, name: "jq" },
  { id: 6, name: "jr" }
];
let arr = {id: 7, name: 'yy'}
console.log(array.splice(1,1, arr));//[ { id: 2, name: 'jc' } ]
console.log(array);// [ { id: 5, name: 'jk' },{ id: 7, name: 'yy' }, { id: 3, name: 'jg' }, { id: 4, name: 'jp' },{ id: 1, name: 'jq' },{ id: 6, name: 'jr' } ]

splice()方法直接返回修改的内容,第一个log返回的就是删除的元素,如果第二参数为0或者为负数的时候则会返回一个空的数组,第二个log是改变后的数组。该方法会将原数组修改!

08、Array.prototype.shift()

shift()方法会将数组的第一个元素进行删除,然后返回删除的元素(如果数组为空将会返回undefined),该方法会修改数组的长度 粟子:

let array = [
  { id: 5, name: "jk" },
  { id: 2, name: "jc" },
  { id: 3, name: "jg" },
  { id: 4, name: "jp" },
  { id: 1, name: "jq" },
  { id: 6, name: "jr" }
]
console.log(1,array.shift())//1 { id: 5, name: 'jk' }
console.log(2,array)//2 [ { id: 2, name: 'jc' },{ id: 3, name: 'jg' },{ id: 4, name: 'jp' },{ id: 1, name: 'jq' },{ id: 6, name: 'jr' } ]

09、Array.prototype.unshift()

unshift()该方法则是在数组的开头添加一个或者多个元素

粟子:

let array = [
  { id: 5, name: "jk" },
  { id: 2, name: "jc" },
  { id: 3, name: "jg" },
  { id: 4, name: "jp" },
  { id: 1, name: "jq" },
  { id: 6, name: "jr" }
]
let arr = { id: 2, name: 'yy' }
console.log(1,array.unshift(arr))//7
console.log(2,array)//2 [ { id: 2, name: 'yy' },{ id: 5, name: 'jk' },{ id: 2, name: 'jc' },{ id: 3, name: 'jg' }{ id: 4, name: 'jp' },{ id: 1, name: 'jq' },{ id: 6, name: 'jr' } ]

10、Array.prototype.reverse()

reverse()方法用翻转数组元素的位置,然后返回该数组

let arr = [1,2,3,4,5]
console.log(arr.reverse())//[5,4,3,2,1]

11、Array.prototype.indexOf()

indexOf()方法用于给定的元素然后从数组开头查找数组,如果存在则返回该元素存在数组的下标,不存在则返回-1

简单的粟子:

let array = [1,2,3,4,5,6,7,8,9]
console.log(array.indexOf(3))//2

第二个粟子:(简单的去重)

let array = [1,2,3,4,5,1,2,6,8,3,8,9]
function arr(arr) {
if(arr.length === 0 ) return
let n = [];
for(let i = 0; i<arr.length; i++) {
  if(n.indexOf(arr[i]) === -1) {
    n.push(arr[i])
  }
}
return n
}
console.log(arr(array))//[ 1, 2, 3, 4, 5, 6, 8, 9 ]

12、Array.prototype.lastIndexOf()

lastIndexOf()方法从数组的末端开始按给定的元素进行查找,查找到则返回所在的下标,不存在则返回-1;

粟子:

var arr1 = [1,2,3,4,5]
console.log(arr1.lastIndexOf(3))//2

迭代

1、Array.prototype.forEach()

forEach()方法对数组中的每个元素执行一次所写的回调函数(注意,一旦开始循环中途无法跳出循环)

回调函数接收三个参数

数组当前项值

数组当前项的下标

当前数组 简单的粟子:

var words = ['one', 'two', 'three', 'four'];
words.forEach((item, index) =>{
  if(item === 'two') {
        words.splice(index, 1)
  }

});
console.log(words)//[ 'one', 'three', 'four' ]

2、Array.prototype.map()

map()方法会将该方法迭代后返回的新数组

简单的粟子:

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

let arrs = arr.map(item => item + 10)
console.log(arrs)//[ 11, 12, 13, 14, 15, 16 ]

经典的粟子:

let a = [1,2,3].map(parseInt)
a?

a等于多少呢,有的答案可能是123,有的答案又可能是别的,而且这是一个经典的面试题,是不是刚刚看的时候觉得特别简单一下子就给出了答案了呢!

是不是很意外?还是说这个就是你意想中的事情呢?根据MDN中介绍:是因为通常的情况下我们的回调函数是接受一个参数,但是接受一个参数并不代表map()方法只给回调函数只传一个参数而已,而上面的例子是因为parseInt平常我们使用的时候大都传一个参数进行转换,但是parseInt是可以接受两个参数的,只不过第二个参数为二进制而已,所以第二个参数则会变成二进制,那么第三个参数parseInt则会忽略,所以返回这个答案!

3、Array.prototype.some()

some()方法用于判断回调函数中逻辑而返回true还是false

粟子:

var arr = ['apple', 'banana', 'mango', 'guava']

checkarr = (arr, val) => {
    return  arr.some(item => val === item)
}
console.log(checkarr(arr, 'apple'))//true

4、Array.prototype.reduce()

reduce()方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终为一个值

第一个值为累加器(上一次回调函数返回的值/初始为第一个值)

第二个值为当前值

第三个值为当前下标

第四个值为当前数组 简单的粟子:

var arr = [1, 2, 3, 4, 5]

const data = arr.reduce((prev, curr) => prev + curr )
console.log(data)//15

合并数组里面对象的值并累加(结合find一起使用):

let tableNetWorkData = [
{'newLocker': 6,'newSection': -2,'newSite': 1,'partnerShip': "self"},
{'newLocker': 5,'newSection': 24,'newSite': 1,'partnerShip': "self"},
{'newLocker': 3,'newSection': 65,'newSite': 1,'partnerShip': "sell"},
{'newLocker': 1,'newSection': 38,'newSite': 1,'partnerShip': "agent"},
{'newLocker': -6,'newSection': 4,'newSite': 1,'partnerShip': "agent"},
{'newLocker': 8,'newSection': 22,'newSite': 1,'partnerShip': "lease"},
{'newLocker': 15,'newSection': -2,'newSite': 1,'partnerShip': "self"},
]

let result = tableNetWorkData.reduce((per, currNext) => {
      let pers = per.find( perItem => currNext.partnerShip === perItem.partnerShip );
      if(pers) {
        pers.newLocker += currNext.newLocker;
        pers.newSection += currNext.newSection;
        pers.newSite += currNext.newSite;

      } else {
        let newPers = {
          newLocker: currNext.newLocker,
          newSection: currNext.newSection,
          newSite: currNext.newSite,
          partnerShip: currNext.partnerShip
        }
        per.push(newPers)
      }
      return per
    }, []);
    console.log(result)

结果如下:

再来一个数组去重:

let arr = [1,2,2,3,4,5,5,6,8,7,7,9,8]

let result = arr.reduce( (prev, curr) => {
      if(prev.length === 0 || prev[prev.length - 1] !== curr) {
            prev.push(curr)
      }
      return prev
}, [])
console.log(result)

看结果:

5、Array.prototype.every()

every()方法用于检测数组所有元素是否通过指定的函数的逻辑操作,通过则返回true否则返回false。注意空数组则无论什么逻辑都将返回true

回调函数接通常收三个参数:

当前值

当前值的下标

原数组

简单的粟子:

var arr = [1, 30, 39, 21, 10, 13];

console.log(arr.every(curr => { return curr < 45 }));
// expected output: true

6、Array.prototype.filter()

filter()方法就是一个过滤原数组的方法返回需要的元素组成的新数组,想象成一个漏斗然后过滤一些符合的元素!(不会改变原数组)

当前值

当前值的下标

原数组

粟子:

let fruits = ['apple', 'banana', 'grapes', 'mango', 'orange']
let filterindexOf = function (query){
return fruits.filter(item => {
return item.toLowerCase().indexOf(query.toLowerCase())> -1
})
}
console.log(filterindexOf('an'))//["banana", "mango", "orange"]

7、Array.prototype.toString()

toString()方法就是将数组元素转化为字符串

粟子:

var array1 = ['ca', 'ba', 'a', '1a'];

console.log(array1.toString());// "ca,ba,a,1a"

8、Array.prototype.find()

find() 方法返回数组中满足提供的测试函数的第一个元素的值

当前值

当前值的下标

原数组

粟子:

let arr = [
    {name: 'apples', value: 2},
    {name: 'bananas', value: 0},
    {name: 'cherries', value: 5}
];

let res =arr.find ((item)=> { 
    return item.name === 'bananas';
})

console.log(res)//{ name: "bananas", value: 0 }

总结

对于数组在我们平常对数据的一些操作都大都避免不了使用数组对数据进一步的逻辑操作,所以对于数组的一些方法都要熟悉熟练的使用,只有熟练的使用数组各种方法才能在后端返回的数据进行一梭子的操作完成业务操作甚至是比较骚的操作,同时在使用数组的方法的时候避免给自己挖一些不必要的坑,我们要严格按照规范使用数组的方法这样才不会出现一些神都看不懂的bug,当然文章所介绍的都是平常使用的一些方法,数组还有其他的方法没有写出来,需要的再自己查找了,如有错误万望指出,万分感谢!