笔记 - JS数组

109 阅读4分钟

数组

JavaScript数组有别于其他语言中典型的数组,可以说是用Object模拟出类似数组的结构,本质上区别很大。

典型数组:

  • 元素类型相同。比如Java中的数组,String Array中所有元素皆为String,Int Array中皆为Int。
  • 使用连续的内存存储。不连续的不是array,而是linked list。
  • 通过数字下表获取元素。arr[0]即为数组arr中下标为0的元素。

JavaScript数组:

  • 数组内元素的类型可以不同。比如[1,2,3,4,x]
  • 内存不一定是连续的,因为对象是随机储存的
  • 不能通过数字下表,而是字符串下表获取元素
  • 数组可以有任何的key JavaScript数组只提供浅拷贝。

浅拷贝与深拷贝

  • 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象

  • 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。 如图所示:

image.png image.png

参考:浅拷贝与深拷贝

创建数组

// 新建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:[]} )