数组对象
-一种特殊的对象
JS其实没有真正的数组
-只是用对象模拟数组
JS的数组不是典型数组
典型的数组
- 元素的数据类型相同
- 使用连续的内存存储
- 通过数字下表获取元素
但JS的数组不这样
- 元素的数据类型可以不同
- 内存不一定是连续的 (对象是随机存储的)
- 不能通过数字下标,而是通过字符串下标
- 这意味着数组有任何key比如
let arr = [1,2,3] arr['xxx'] = 1 //这样也是可以的 复制代码
创建一个数组
新建
let arr = [1,2,3] //简写形式 let arr = new Array(1,2,3) //正规形式,只是对理解数组有帮助 let arr = new Array(3) //这里的3是长度,是length,而不是元素内容,多个写的时候才是内容 复制代码
转化
let arr = '1,2,3'.split(',') //以,进行分割 let arr = '123'.split('') //将每个元素直接分割 Array.from('123') //直接就是['1','2','3'] 复制代码
伪数组
let divList = document.querySelectorAll('div') 复制代码
- 伪数组的原型链中并没有数组的原型
应该是 数组 => 数组原型 => 对象原型
伪数组是: 数组 => 对象原型
没有数组共用属性的【数组】
-就是伪数组
合并两个数组,得到新数组
arr1.concat(arr2) 复制代码
截取一个数组的一部分
arr1.slice(1) //从第二个元素开始 arr1.slice(0) //全部截取 复制代码
注意:JS只提供浅拷贝
增删改查 -数组中的元素
删元素
跟对象一样
let arr = ['a','b','c'] delete arr['0'] arr //[empty , 'b' , 'c'] 复制代码
- 神奇,数组的长度没有变
只是清除数据元素本身
稀疏数组
如果直接改length可以删除元素吗
let arr = [1,2,3,4,5]; arr.length = 1; 复制代码
- 我丢???这都可以
JS就是这么神奇!!
删除头部的元素
arr.shift() //arr被修改,并返回被删元素 复制代码
删除尾部的元素
arr.pop() //arr被修改,并返回被删元素 复制代码
删除中间的元素
arr.splice(index,1) //删除index的一个元素 arr.splice(index,1,'x')//并在删除位置添加'x' arr.splice(iindex,1,'x','y')//并在删除位置添加'x','y' 复制代码
查看所有元素
查看所有元素名
let arr = [1,2,3,4,5]; arr.x = 'xxx' Object.keys(arr) for(let key in arr){ console.log(`${key} : ${arr[key]}`) } //for因访问对象居多 复制代码
查看数字(字符串)属性名和值
for(let i = 0; i< arr.length;i++){ console.log(`${i} : ${arr[i]}`) } //查看数组较推荐 复制代码
你要自己让i从0增长到length-1
arr.forEach(function(item,index){ console.log(`${index} : ${item}`) }) 复制代码
也可以用forEach/map等原型上的函数
forEach是一个坎
自己写forEach才能理解forEach
function forEach(array, fn) { for (let i = 0; i < array.length; i++) { fn(array[i], i, array) } } forEach(['a', 'b', 'c'], function (值, 下标, 数组) { console.log(值, 下标, 数组) }) 复制代码
forEach用for方位array的每一项
对每一项调用fn(array[i],i,array)
为什么要传入array呢?不为什么,规定如此
查看单个属性
跟对象一样
let arr= [111,22,3] arr[0] //是111 复制代码
索引越界
arr[arr.length] === undefined arr[-1] === undefined 复制代码
举例
for(let i = 0 ; i<= arr.length; i++){ console.log(arr[i].toString) } //会报错,因为 i <= arr.length //最后会循环到 i[arr.length] 这一层,也就是会越界了 复制代码
报错Cannot read property 'toString' of undefined
意思是你读取了undefined的toString属性
不是toString是undefined
x.toString()其中x如果是undefined就会报这个错
查找某个元素是否在数组里
arr.indexOf(item) //存在返回索引,否则返回-1 复制代码
使用条件查找元素
arr.find(item=> item%2 === 0) //找第一个偶数 复制代码
使用条件查找元素的索引
arr.findIndex(item => item%2 === 0) //找第一个偶数的索引 复制代码
增加数组中的元素
在尾部加元素
arr.push(newItem) //修改arr,返回新长度 arr.push(item1,item2) //修改arr,返回新长度 复制代码
在头部加元素
arr.unshift(newItem) //修改arr,返回新长度 arr.unshift(item1,item2) //修改arr,返回新长度 复制代码
在中间添加元素
arr.splice(index,0,'x') //在index处插入'x' 0的意思是删除0个,也就是不删除 arr.splice(index,0,'x','y') //在index处插入'x','y' 复制代码
修改数组中的元素
反转顺序
arr.reverse() //修改原数组 复制代码
自定义顺序
arr.sort((a,b) => a-b) 接收两个参数 返回 1 0 -1 复制代码
map
map()
方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
例如可以返回原始数组中每个元素的平方:
let arr = [4, 9, 16, 25] let arr2 = arr.map( (item) => //唯一的参数是数组中的每个值 Math.pow(item,2) //调用求平方方法 ) console.log(arr2) //[16, 81, 256, 625] 复制代码
也可返回一个数组的平方根:
let arr = [4, 9, 16, 25] let arr2 = arr.map( (item) => Math.sqrt(item) //调用求平方根方法 ) console.log(arr2) // [2, 3, 4, 5] 复制代码
注意:** map() 不会改变原始数组。
filter
filter()
方法创建一个新数组, 新数组中的元素是通过检查指定数组中符合条件的所有元素。
过滤掉太短的字符串:
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']; const result = words.filter(word => word.length > 6 //过滤掉小于6个字母的 ); console.log(result); // ["exuberant", "destruction", "present"] 复制代码
过滤掉成绩不及格的分数:
let scores = [95,91,59,55,42,82,72,85,67,66,55,91] let scores2 = scores.filter( item => item >60 ) console.log(scores2) //[95, 91, 82, 72, 85, 67, 66, 91] 复制代码
注意:** filter() 也不会改变原始数组。
reduce
reduce()
方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
语法:
array.reduce( ( 初始值,当前元素, 当前元素的索引, 当前元素所属的数组对象) =>{ //代码 }, 传递给函数的初始值) 必需。初始值, 或者计算结束后的返回值。 ******* 必需。当前元素 ********** 可选。当前元素的索引 可选。当前元素所属的数组对象 可选。传递给函数的初始值 ********** 复制代码
算出所有奇数之和:
let scores = [95,91,59,55,42,82,72,85,67,66,55,91] let sum = scores.reduce((sum, item)=>{ //sum是每轮相加后的保存者 item是当前元素 if(item % 2){ return sum += item //如果是奇数,返回相加之和 } return sum },0) //此0是规定sum的初始值 console.log(sum) 复制代码
注意:就算不是奇数,我们也要返回sum本身,不能返回0,因为他每次接收到的值就是下一轮开始的值, 如果我们返回0,相当于把之前累加的都清空掉了
计算元素四舍五入后的和:
let arr = [15.5, 2.3, 1.1, 4.7] let sum = arr.reduce((sum, item) => { //首先还是sum,item。sum初始值在最后的0。 return sum += Math.round(item) }, 0) console.log(sum) 复制代码
reduce是可以替代map与filter的。
替代map: (计算数组中每个元素的平方,并返回新的函数)
let arr1 = [4, 9, 16, 25] let arr2 = arr1.reduce((arr2,item) => {//传入arr2数组,与arr1的每个元素 return arr2.concat(Math.pow(item,2)) },[]) //这里我们将arr2的初始值定位空数组 console.log(arr2) //[16, 81, 256, 625] 复制代码
注意://由于要返回数组,我们要arr2用concat这个方法连接arr1中的item元素,并返回 代替filter: (过滤掉太短的字符串)
let scores = [95,91,59,55,42,82,72,85,67,66,55,91] let scores2 = scores.reduce((scores2,item)=>{ return scores2.concat(item>60?item:[]) 个空数组,不能连接null,null会占位置 },[]) console.log(scores2) //[95, 91, 82, 72, 85, 67, 66, 91] 复制代码
注意:如果大于60就连接到数组里,不然就连个空数组,不能连接null或undefined,null和undefined会占位置,变成['1',null,'2','3',null,'4']
这个样子
总结
js中没有真正的数组,它的数组不是典型的数组
reduce在刚刚上手会比较难,多用几次就好了。
数组中最强大的就是splice和reduce,一定要用好这两个。
map()是n变n,即map里有多少元素,返回的数组就是多少元素,是对里面每个元素进行加功
filter()是n变少,过滤掉一些元素
reduce()是n变一,将所有元素进行累加