典型数组与JS数组
典型的数组
-
典型的数组中的元素数据类型相同
-
典型的数组使用连续的内存存储

- 通过数字下标获取元素
JS的数组
-
元素的数据类型可以不同
-
内存的存储不一定是连续的(可以是:0,1,2;也可以是0,2,1)

-
获取元素通过的是字符串,而非数字下标(因为数组其实就是一个比较特别的对象)
-
数组可以拥有任意的key,不一定只是数字(实际上是字符串)
-
let arr = [1,2,3] arr['xxx'] = 4 console.log(arr) // [1, 2, 3, xxx: 1],只有数字的属性名会自动隐藏
-
JS数组的实质
- JS数组实际上就是个拥有特定结构的对象,属性名都是数字的形式(类型其实还是字符串),还有一个叫 length 的属性
- 在使用数组的过程中我们可以发现其身上都是对象的影子
JS的伪数组
- 拥有类似数组的结构,但是原型链中并没有Array的原型的对象,称之为伪数组
let divList = document.querySelectorAll('div')这里生成的是一个节点列表,但是原型链中并没有Array的原型。
JS数组的创建
创建一个数组
let arr = [1,2,3]这是数组的简单创建方式,可以感觉到和 {} 创建对象有异曲同工之妙。let arr = new Array(1,2,3)这是数组的规范创建方式,直接传入数组的元素作为参数(传入的元素数量最少2个,否则会变成下面3.的情况)。let arr = new Array(3)当传入的参数只有一个的时候指定的是创建数组的长度。
非数组转化成数组
-
通过字符串的 split() 方法将字符串转化成数组。
let arr = '1,2,3'.split(',') // 通过 , 号将字符串分割 ["1","2","3"] let arr = '123'.split('') // 通过空字符串将字符串分割 ["1","2","3"] -
Array.from()这个方法可以将具有类似数组结构的对象或字符串转换成数组,除了属性名是数字以外,还要有一个length的属性来确定转换后的数组的长度。这个方法最常用于将伪数组变成真数组。Array.from({"1":"a","2":"b","3":"c","ss":"ss",'length':5}) // [undefined, "a", "b", "c", undefined]
数组修改成新数组
-
arr1.concat(arr2)将两个数组合并(arr1在前,arr2在后),返回一个新的数组,arr1、arr2没有被修改。 -
截取一个数组的一部分,形成一个新数组。
let arr1 = [1,2,3,4,5,6] let arr2 = arr1.slice(2,3) // [3] let arr3 = arr1.slice(2) // [3,4,5,6] let arr4 = arr1.slice(0) // 全部截取,相当于复制一个数组 // 第一个参数是截取的起始索引(截取内容包括起始点);第二个参数是截取的终点(截取内容不包括终点),默认是arr1.length截取至末尾。 -
注意:所有JS原生API都只提供浅拷贝,即只拷贝了对象的引用地址。
// 以 Array.prototype.slice()为例 let arr = [{'name':'Jack',age:18}, {'name':'Tom',age:19}, {'name':'Lich',age:20} ] let arr2 = arr.slice(0) // 复制一份arr给arr2 arr[0].name = 'John' arr[0].name // John arr2[0].name // John 而不是 Jack
JS数组的增删查改
删元素
2种虚假的删除元素
-
像对象一样,通过delete来删除数组的中的元素
let arr = ['a','b','c'] delete arr[0] arr // [empty,'b','c'] 删除了元素的内容,length没有改变,仍然是3个元素。当一个数组中实际的元素与length并不匹配,我们就将它称作稀疏数组。
显然delete删除数组元素的结果并不是我们想要的。
-
既然1.中的方法没有改变length,那把length也改了行不行?
let arr = ['a','b','c'] arr['length'] = 1 arr // ['a'] 可以发现length也是可以修改的 let arr2 = ['a','b','c'] delete arr2[1] // 尝试使用delete并配合length的修改来看能否达到想要的效果 arr2['length'] = 2 arr2 // ['a',empty] 然而不能修改length可以影响数组的长度,从而影响到元素,但这也不能达到理想的结果
而且不要随意修改length。
真实的删除元素
-
arr.shift()删除最前面的元素,并返回被删除的元素,原来的数组被修改。 -
arr.pop()删除最后面的元素,并返回被删除的元素,原来的数组被修改 -
splice()方法从数组中间删除元素,这个方法也可以实现shift()pop()的效果arr.splice(index,number) // 从arr的索引为index的元素开始,往后删除number个元素,并返回删除的元素 arr.splice(index,number,'x','y') // 在删除number个元素后,在删除的位置插入新元素'x','y' let arr = ['a','d','e','c'] arr.splice(1,2,'b','f') arr // ['a','b','f','c']
查看元素
查看所有的元素
-
Object.key()与for in 循环因为数组也是对象,所以我们可以使用对象的方法,
Object.keys(arr)来查看我们数组的所有的属性名。或者使用 for in 循环进行遍历。let arr = [1,2,3,4,5,6] arr['x'] = 'xxx' Object.keys(arr) // ["0", "1", "2", "3", "4", "5", "x"] for(let i in arr){ console.log(`${i}:${arr[i]}`) }上面的两种方法会遍历所有的属性名,包括我们乱给的 'x' 这个属性名,但有时候我们只希望获得那些数字的属性名。
-
遍历数组
- 传统的遍历数组
for(let i = 0;i<arr.length;i++){ // 注意i的范围 console.log(`${i}:${arr[i]}`) } // 这样我们就只遍历了那些数字的属性名,而不会遍历出不符合规则的属性的名。- forEach循环遍历数组,及其原理
// forEach的回调函数的第一个参数是当前循环的数组的值,第二个参数是当前循环的数组的索引 arr.forEach(function(item,index){ console.log(`${index}:${item}`) }) // forEach循环也不会遍历出非数字形式的属性名 // forEach的原理: function forEach(array, fn) { for (let i = 0; i < array.length; i++) { fn(array[i], i, array) } }-
for循环与forEach的最大区别
for循环里面可以有break和continue 而 forEach中没有。
for循环是一个关键字,只有块级作用域,而forEach是一个函数是一个函数作用域 。
查看与查找单个元素
-
正常查看与索引越界
-
通过
arr[index]即可查看到对应索引的属性值,注意index最后会被转换成字符串 -
索引越界:
索引越界及查看的索引并不在数组的索引范围内
arr[-1] // undefined arr[arr.length] // undefined
-
-
查找数组中的属性
// 1. 查找某个元素是否在数组里面 arr.indexOf(item) // 存在,则返回索引值;不存在,则返回-1 // 2.使用条件查找元素 arr.find((item)=>{return item%2===0}) // 返回数组中的第一个偶数元素 // 遍历数组,当函数第一次返回true的时候,将正遍历的数组的元素返回 // 3.使用条件查找元素的索引 arr.findIndex((item)=>{return item%2===0}) // 返回数组中的第一个偶数元素的索引
增加与修改数组中的元素
增加元素
// 1.在尾部加元素
arr.push(newitem) // 修改arr,元素增加,length也会增加。返回数组新的长度。
// 2.在头部加元素
arr.unshift(newitem) // 修改arr,元素增加,length也会增加。返回数组新的长度。
// 3.在中间添加元素 (删除和添加都是使用splice方法)
arr.splice(index,0,'newitem1','newitem2') // 删除元素数量为0即不删除,直接插入新元素
-
上面的方法和
arr[index] = newitem的区别:上面的操作不会产生稀疏数组,而
arr[index] = newitem这种操作容易产生稀疏数组,所以增加元素都使用上面的3种方法。
修改元素
- 直接
arr[index] = 'xxx'即可修改元素。
数组变换
-
反转数组,reverse
let arr = [1,2,3,4,5] arr.reverse() // [5, 4, 3, 2, 1],反转数组,并返回反转后的数组 -
按自定义要求整理数组,sort
- 当不传入回调函数的时候,默认将元素换为字符串,然后比较它们的UTF-16代码单元值序列
- 当传入回调函数的时候,按照要求的比对进行数组整理
let arr = [1,2,3,4,5] arr.sort(function(a,b){ // 第一个参数是前面用于比较的元素,第二个参数是后面用于比较的元素 return -1 // 根据返回值:负数(-),a在b前;0,ab位置不变;正数(+),b在a前面 }) -
整体变换,map
- 原数组没有被修改。将原数组每一个元素都执行一次函数,并返回一个包含所有元素执行函数后的结果的数组。
let arr = [1,2,3,4,5] arr.map(x=> x*2) // [1,4,6,8,10] arr // [1,2,3,4,5] -
过滤数组,filter
- 原数组没有被修改。创建一个新的空数组,将原数组元素从头开始,执行函数,若返回true则将该元素放入新的数组,最终返回该新的数组。
let arr = [1,2,3,4,5] arr.filter(x=> x%2===0) // [2,4] 筛选数组中的偶数 arr // [1,2,3,4,5] -
结果汇总,reduce
- 原数组每个元素执行一次回调函数,并根据函数将结果汇总为一个返回值。
- “一个返回值”不定就只是一个值,也可以是一个包含多个对象的数组[{},{},{}]
let arr = [1,2,3,4,5] // reduce函数:第一个参数是回调函数;第二个参数是累计值的初始值,如果没有则使用数组的第一个元素作为累计值的初始值。 let sum = arr.reduce(function(result,item){ // 回调函数:第一个参数是累计值;第二个参数是当前值 if(item%2===0){ return result+=item }else{ return result } },0) sum = 6 // 求数组中的偶数和