数组
JavaScript数组有别于其他语言中典型的数组,可以说是用Object模拟出类似数组的结构,本质上区别很大。
典型数组:
- 元素类型相同。比如Java中的数组,String Array中所有元素皆为String,Int Array中皆为Int。
- 使用连续的内存存储。不连续的不是array,而是linked list。
- 通过数字下表获取元素。arr[0]即为数组arr中下标为0的元素。
JavaScript数组:
- 数组内元素的类型可以不同。比如[1,2,3,4,x]
- 内存不一定是连续的,因为对象是随机储存的
- 不能通过数字下表,而是字符串下表获取元素
- 数组可以有任何的key JavaScript数组只提供浅拷贝。
浅拷贝与深拷贝
-
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
-
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。 如图所示:
参考:浅拷贝与深拷贝
创建数组
// 新建array
let arr = [];
// 新建一个含有1,2,3的array
let arr = new Array(1,2,3);
// 新建一个length为3的array
let arr = new Array(3);
转化
string to array
let arr = '1,2,3'.split(',');
let arr = '123'.split('');
Array.from('123');
// result: ["1", "2", "3"]
伪数组
形似数组,但原型链中没有数组的原型。
例如:
let divList = document.querySelectorAll('div');
返回的结果看似是数组实际并无数组原型。
合并数组
let arr1 = ['a','b','c'];
let arr2 = [1,2,3];
let arr3 = arr1.concat(arr2);
// result: (6) ["a", "b", "c", 1, 2, 3]
截取数组
slice()
// 全部截取
let arr = [1,2,3];
r1 = arr.slice(0);
// < (3) [1, 2, 3]
// 从第二个元素开始截取
r2 = arr.slice(1);
// < (2) [2, 3]
注意:js提供的拷贝为浅拷贝
增删改查
增加元素
尾部增加
arr.push(item1, item2, item3, ...);
数组尾部增加元素,返回新长度。
头部增加
arr.unshift(item1, item2, item3, ...);
数组头部增加元素,返回新长度。
指定index添加
arr.splice(index,0,item1, item2, item3, ...);
反转数组
arr.reverse()
删除元素
delete
// 删除第一个元素
let arr = ['a','b','c'];
delete arr[0];
arr
// < [empty,'b','c']
delete 能够删除指定元素,但数组的长度不因此改变,只会留空。这种含有空元素的数组也被称为稀疏数组。 JS中稀疏数组容易导致Bug。
修改length
let arr = [1,2,3,4,5];
arr.lenght = 1;
arr
// [1]
可以通过截短length将数组缩短,但此方法不可取。
shift() 删除头部元素
删除头部元素,并返回被删元素
let arr = [1,2,3,4,5];
arr.shift()
// < 1
pop() 删除尾部元素
删除尾部元素,并返回被删元素
let arr = [1,2,3,4,5];
arr.pop()
// 5
splice() 删除指定位置的元素
splice(startIndex, deleteCount, addItem1, addIterm2, ... )
// 删除一个元素
splice(index,1);
// 删除并添加 'x'
splice(index,1,'x');
// 删除并添加 'x', 'y'
splice(index, 1, 'x', 'y');
查看元素
查看所有属性名
Object.keys(arr)
查看所有属性值
Object.values(arr)
查看属性名和属性值
for
for(let i = 0; i < arr.length; i++){
console.log(`${i}: ${arr[i]}`)
}
forEach:访问数组的每一项,返回item,index
arr.forEach(function(item, index){
console.log(`${index}: ${item}`)
})
索引越界
arr[arr.length] === undefined
arr[-1] === undefined
for(let i = 0; i<= arr.length; i++){
console.log(arr[i].toString());
}
// 报错
报错内容如果为 Cannot read property 'toString' of undefined 则证明索引大于array长度,array有自动转化key值为string(即toString)进行查询的能力,如果查到不存在的就为undefined,无法转化,因而报错。
查询单个属性
- 查找某个元素是否存在于数组中
arr.indexOf(item)
true: 返回索引
else: 返回 -1 - 条件查找元素
arr.find(item => (...))
true: 返回元素
else: 返回undefined - 条件查找元素索引
arr.findIndex(item => (...))
true: 返回元素索引
else: 返回undefined
sort() 数组排序
- 如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 "Banana" 会被排列到 "cherry" 之前。当数字按由小到大排序时,9 出现在 80 之前。
e.g. 令数组内数字从大到小排列
arr.sort((a,b) => a-b)
解释:
a > b, a-b > 0, return true, 执行排序操作
a < b, a-b <0, return false, 不执行排序操作
a == b, return 0, 不执行排序操作
数组变换
map()
map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
const map1 = array1.map(x => x * 2);
// 把数字变成星期
let arr = [0,1,2,2,3,3,3,4,4,4,4,6]
let arr2 = arr.map((day) => {
let week = ['周日','周一','周二','周三','周四','周五','周六'];
return week[day];
}
)
console.log(arr2)
filter()
filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
const result = words.filter(word => word.length > 6);
let scores = [95,91,59,55,42,82,72,85,67,66,55,91]
let scores2 = scores.filter(score => score > 60)
console.log(scores2)
reduce()
reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10
let scores = [95,91,59,55,42,82,72,85,67,66,55,91]
let sum = scores.reduce((sum, n)=>{
return sum = sum + (n % 2 === 1 ? n :0 );
},0)
console.log(sum) // 奇数之和:598
一道面试题:
将以下数组转换为指定的对象
// array
let arr = [
{名称:'动物', id:1, parent:null},
{名称:'狗', id:2, parent:1},
{名称:'猫', id:3, parent:1}
]
// object
{
id:1, 名称: '动物', children:[
{id:2, 名称:'狗', children:null},
{id:3, 名称:'猫', children:null}
]
}
// solution
arr.reduce((result, item) => {
// accumulator
if(item.parent === null){
result.id = item.id;
result['名称'] = item['名称'];
}
else{
result.children.push(item);
delete item.parent;
item.children = null;
}
return result;
},
// currentValue, 也即初始值
{id:null, children:[]} )