JavaScript数组

239 阅读4分钟

数组对象 一种特殊的对象

JS其实没有真正的数组,只是用对象模拟数组

  • 元素的数据类型可以不同
  • 内存不一定是连续的
  • 不能通过数字下标,而是通过字符串下标
  • 数组可以有任意的key
let arr = [1,2,3]
arr['name'] = 'maike'
Object.keys(arr) //得到的是["0", "1", "2", "name"]

创建一个数组

新建

let arr = [1,2,3] //中括号简写

let arr = new Array(1,2,3) //构造函数方式

let arr = new Array(3) //构造函数的另一个使用,生成长度为3的数组

let arr1 = [1,2]
let arr2 = [3,4]
arr1.concat(arr2) //通过concat函数得到[1,2,3,4],返回一个新数组,不改变原数组

let arr = [1,2,3,4,5]
arr.slice(2) //通过slice函数得到[3,4,5],参数为切片开始的下标,不包含下标本身
let arr2 = arr.slice(0) //利用slice浅拷贝一个数组

转化

let arr = '1,2,3'.split(',') //通过字符串的split函数创建数组
let arr = '123'.split('') //利用空字符串分隔
Array.from('123') //es6新增API,有0,1,2,3等下标,及length属性,就可以转化为数组

伪数组

let div = document.querySelectorAll('div')
div.__proto__ === Array.prototype //返回false,原型链没有数组的原型
//没有数组原型的公有属性的即为伪数组

数组的增删改查

和对象一样

let arr = [1,2,3]
delete arr['0']
arr //[empty,'2','3'],但arr.length仍然为3,这种办法不太适合数组

改变数组的length

let arr = [1,2,3]
arr.length = 1
arr //[1],改变数组的length可以修改数组内容,但不推荐使用

删除头部的元素

let arr = [1,2,3,4]
arr.shift() //1 修改数组,并返回被删除元素
arr //[2,3,4] length会自动修改

删除尾部的元素

let pop = [1,2,3,4]
arr.pop() //4 修改数组,并返回被删除元素
arr //[1,2,3] length会自动修改

删除中间的元素

let arr = [1,2,3,4]
arr.splice(1,1) //修改数组,返回被删除元素组成数组
//第一个参数为index,第二个为删除个数,删除index为1的一个元素
arr //[1, 3, 4],length会自动变更

arr.splice(0,1,'hi') //删除数组第0个开始的一个元素,并添加'hi'
arr //["hi", 2, 3, 4]

arr.splice(0,1,'wqeqweqw',12312321) //删除数组第0个开始的一个元素,并添为'wqeqweqw',12312321
arr //["wqeqweqw", 12312321, 2, 3, 4]

遍历数组

查看所有元素名

let arr = [1,2,3,4]
Object.keys(arr) //Object.keys函数可查看
for(key in arr){console.log(key + ':' + arr[key])} //for...in...可查看

查看数字属性名和属性值

//for循环可实现所有数组操作
let arr = [1,2,3,4]
for(let i = 0;i<arr.length;i++){
    console.log(i + ':' + arr[i])
}

//使用forEach函数
arr.forEach(function(key,value){
    console.log(key,value)
})

//自己实现forEach
function forEach(array,fn){
    for(let i=0;i<array.length;i++){
        fn(i,array[i])
    }
}

forEach(arr,function(key,value){
    console.log(key,value)
})

//for循环和forEach的差别,for循环可实现break/continue循环

查看单个属性

//和对象一样
let arr = [1,2,3]
arr[0] //0为字符串

//索引越界,访问不存在的index
arr[-1]
arr[arr.length]

查看一个元素是否存在数组里

//使用indexOf
let arr = [1,2,3,4]
arr.indexOf(1) //1 如果存在,返回元素所在下标
arr.indexOf(10) //-1 如不存在,返回-1

//使用find
arr.find(function(ele){
    return ele % 2 === 1
})
//返回符合条件的第一个元素的值,而不是下标

//使用findIndex
arr.findIndex(function(ele){
    return ele % 2 === 1
})
//返回符合条件的第一个的下标

增加数组中的元素

//使用push在尾部添加元素,length会自动变,返回新长度
let arr = [1,2,3]
arr.push(4)
arr //[1,2,3,4]

arr.push(5,6,7,8)
arr //[1,2,3,4,5,6,7,8]

//使用unshift在头部添加元素,length会自动变,返回新长度
let arr2 = [1,2,3]
arr2.unshift(0)
arr2 //[0,1,2,3]

arr2.unshift(-1,-2)
arr2 //[-1,-2,0,1,2]

//利用splice函数
arr2.splice(3,0,0.1,0.2)
arr2 //[-1,-2,0,0.1,0.2,1,2]

修改数组中的元素

let arr = [1,2,3]
arr[0] = '1212' //根据下标直接修改
arr.splice(0,1,'asdas') //使用splice函数

arr.reverse() //[3,2,1]翻转数组,会修改原来的数组

let name = 'neb'
name.split('').reverse().join('') //ben api结合使用

//自定义顺序
let reArr = [2,5,1,3,4]
reArr.sort() //[1,2,3,4,5] //默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的,sort参数接受一个函数,函数需要两个参数
//返回1表示a大,返回0表示一样大,返回-1表示b大
reArr.sort(function(a,b){
    if(a>b){return -1}
    else if(a===b){return 0}
    else{return 1}
}) //[5,4,3,2,1]

let childList = [
    {name:'mike',age:10},
    {name:'ben',age:8},
    {name:'lily',age:17}
]

childList.sort(function(a,b){
    if(a.age>b.age){return -1}
    else if(a.age===b.age){return 0}
    else{return 1}
})

//等价于
childList.sort((a,b)=>a-b) //如果a-b是正数相当于1,相等相当于0,负数相当于-1

//[ {name: "lily", age: 17}
//{name: "mike", age: 10}
//{name: "ben", age: 8}] 得到的数组根据age字段排序

数组变换 map,filter,reduce

  • map n变n 创建一个新数组,其结果是该数组中的每个元素都调用一次提供的函数后的返回值。
let arr = [1,2,3]
arr.map(value=>value*value) //es6语法,参数只有一个时可省略括号,语句只有一句可以省略花括号及return


//自己实现map
function copyMap(arr,fn){
  	let tempList = []
	for(let i = 0;i<arr.length;i++){
    	tempList.push(fn(arr[i],i,arr))
    }
  	return tempList
}

let a = copyMap([1,2,3],(value,key)=>{
	return value * value                
})
console.log(a) //[1,4,9]
  • filter n变少 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
let arr = [1,2,3,4,5,6]
arr.filter(item => item%2===0) //返回偶数,需要的值返回true,不需要的返回false

//自己实现filter
function copyFilter(arr,fn){
  	let tempList = []
	for(let i = 0;i<arr.length;i++){
    	if(fn(arr[i],i,arr)){
    	    tempList.push(arr[i])    
    	}
    }
  	return tempList
}

let a = copyFilter([1,2,3],(value,key)=>{
	return value % 2 === 0
})
console.log(a) //[1,4,9]
  • reduce n变1 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。reduce可替代map和filter
let arr = [1,2,3,4,5]
arr.reduce((sum,item)=>sum+item,0) //返回15,数组每个元素的相加总和
//使用reduce实现map元素进行平方的例子
arr.reduce((arr,item)=>{
    return arr.concat(item*item)
},[])

//使用reduce实现筛选偶数
let arr2 = [1,2,3,4,5,6]
arr2.reduce((result,item)=>result.concat(item%2===0?item:[]),[]) //[2,4,6]

常见面试题

let arr = [
    {名称:'动物',id:1,parent:null},
    {名称:'狗',id:2,parent:1},
    {名称:'猫',id:3,parent:1}
]
// 数组变成对象
{
    id:1,名称:'动物',children:[
        {id:2,名称:'狗',children:null},
        {id:3,名称:'猫',children:null}
    ]
}

//答案:
arr.reduce((result, item) => {
    if(!result.children){
        result.children = []
    }
    if (item.parent === null) {
        result.id = item.id
        result.名称 = item.名称
    } else {
        delete item.parent
        item.children = null
        result.children.push(item)
    }
    return result
}, {})