JavaScript数组

JavaScript数组

数组(Array)是属于内置对象,数组和普通对象的功能类似,都可以用来存储一些值。不同的是:

  • 普通对象是使用字符串作为属性名,而数组是使用数字作为索引来操作元素。索引:从 0 开始的整数就是索引。

数组的存储性能比普通对象要好。在实际开发中我们经常使用数组存储一些数据(尤其是列表数据),使用频率非常高。

数组创建

在js中有一下几种方式创建数组

使用字面量创建数组

let arr1 = []; // 创建一个空的数组
let arr2 = [1, 2, 3]; // 创建带初始值的数组

使用构造函数创建数组

let arr = new Array(参数);
let arr = Array(参数);

如果参数为空 ,表示创建一个空数组;如果参数是一个数值 ,表示数组的长度;如果有多个参数,表示数组中的元素内容。

let arr1 = [1,2,3]
let arr2 = new Array()
let arr3 = new Array(5)
let arr4 = new Array(1,"hello",{"name":'tom', 'age':12},[3,6])

console.log('arr1 = ' + JSON.stringify(arr1)); // arr1 = [1,2,3]
console.log('arr2 = ' + JSON.stringify(arr2)); // arr2 = []
console.log('arr3 = ' + JSON.stringify(arr3)); // arr3 = [null,null,null,null,null]
console.log('arr4 = ' + JSON.stringify(arr4)); // arr4 = [1,"hello",{"name":"tom","age":12},[3,6]]

以上例子我们可以看出数组中可以存放任意类型的数据,例如字符串、数字、布尔值、对象等。

数组的操作

索引 (下标) :用来访问数组元素的序号,代表的是数组中的元素在数组中的位置(下标从 0 开始算起)。

添加元素

let arr1 = new Array(5)
arr1[1]= 100
arr1[3] = 0
arr1[6] = 2
console.log('arr1 = ' + JSON.stringify(arr1)); // arr1 = [null,100,null,0,null,null,2]

当下标查过定义数组的长度时候, 会把数组的长度扩充

获取元素

如果读取不存在的索引(比如元素没那么多),系统不会报错,而是返回 undefined。

代码举例:

const arr = [21, 22, 23];

console.log(arr[0]); // 打印结果:21
console.log(arr[5]); // 打印结果:undefined

数组长度

可以使用length属性来获取数组的长度(即"元素的个数")。

数组的长度是元素个数,不要跟索引号混淆。

语法:

数组的长度 = 数组名.length;

代码举例:

const arr = [21, 22, 23];

console.log(arr.length); // 打印结果:3

补充:

对于连续的数组,使用 length 可以获取到数组的长度(元素的个数);对于非连续的数组(即"稀疏数组",本文稍后会讲),length 的值会大于元素的个数。因此,尽量不要创建非连续的数组。

修改数组长度

可以通过修改length属性修改数组的长度。

  • 如果修改的 length 大于原长度,则多出部分会空出来,置为 null。

  • 如果修改的 length 小于原长度,则多出的元素会被删除,数组将从后面删除元素。

  • (特例:伪数组 arguments 的长度可以修改,但是不能修改里面的元素,以后单独讲。)

    const arr1 = [11, 12, 13];
    const arr2 = [21, 22, 23];

    // 修改数组 arr1 的 length
    arr1.length = 1;
    console.log(JSON.stringify(arr1)); // [11]

    // 修改数组 arr2 的 length
    arr2.length = 5;
    console.log(JSON.stringify(arr2)); // [21, 22, 23, null, null]

遍历数组

就是把数组中的每个元素从头到尾都访问一次。最简单的做法是通过 for 循环,遍历数组中的每一项。

let arr1 = [1,"dany",12,{"name":"tom","age":12},[33,44]]
for (let index = 0; index < arr1.length; index++) {
    console.log(arr1[index]);
    
}

和其他编程语言相比,JS语言中的数组比较灵活,有许多与众不同的地方。

1、如果访问数组中不存在的索引时,不会报错,会返回undefined。

2、当数组的存储空间不够时,数组会自动扩容。其它编程语言中数组的大小是固定的,不会自动扩容。

3、数组可以存储不同类型数据,其它编程语言中数组只能存储相同类型数据。

4、数组分配的存储空间不一定是连续的。其它语言数组分配的存储空间是连续的。

JS中的数组采用"哈希映射"的方式分配存储空间,我们可以通过索引找到对应空间。各大浏览器也对数组分配的存储空间进行了优化:如果存储的都是相同类型的数据,则会尽量分配连续的存储空间;如果存储的不是相同的数据类型,则不会分配连续的存储空间。

数组解构

解构赋值是ES6中新增的一种赋值方式。

ES5中,如果想把数组中的元素赋值给其他变量,是这样做的:

const arr = [1, 2, [3,4]];
let a = arr[0]; // 1
let b = arr[1]; // 2
let c = arr[2]; // [3, 4]

//我们也可以按照如下方式
let [a, b, c] = [1, 2, [3, 4]];
console.log(a); // 1
console.log(b); // 2
console.log(c); // [3, 4]

注意点:

(1)等号左边的个数和格式,必须和右边的一模一样,才能完全解构。

(2)当然,左边的个数和右边的个数,可以不一样。

解构时,我们也可以给出默认值

let [a, b = 3, c = 4] = [1, 2];
console.log(a); // 1
console.log(b); // 2。默认值被覆盖。
console.log(c); // 4。继续保持默认值。

我们可以使用ES6中新增的扩展运算符打包剩余的数据。如果使用了扩展运算符, 那么扩展运算符只能写在最后。代码举例:

let [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]

数组的方法

数组类型判断

方法 描述 备注
Array.isArray() 判断是否为数组
toString() 将数组转换为字符串 不会改变原数组
join() 将数组转换为字符串,返回结果为转换后的字符串 不会改变原数组
字符串的方法:split() 将字符串按照指定的分隔符,组装为数组 不会改变原字符串
Array.from(arrayLike) 伪数组 转化为真数组
Array.of(value1, value2, value3) 创建数组:将一系列值转换成数组

注意:

(1)获取数组的长度是用length属性,不是方法。关于 length属性,详见上一篇文章。

(2)split()是字符串的方法,不是数组的方法。

isArray() 判断是否为数组
toString()
join()
arr1 = [1,"tom",{"name":"jack","age":12},[22,55]]
console.log(Array.isArray(arr1)) //true 判断是否为数组
console.log(arr1.toString())  // 1,tom,[object Object],22,55 数组转为字符串 也可以用String(arr1)方法
//将数组转换为字符串,返回结果为转换后的字符串(不会改变原来的数组)。 join()方法可以指定一个字符串作为参数,这个参数是元素之间的连接符;如果不指定连接符,则默认使用英文逗号, 作为连接符,此时和 toString()的效果是一致的。
console.log(arr1.join(","))   // 1,tom,[object Object],22,55

伪数组是包含 length 属性的对象或可迭代的对象。伪数组的原型链中没有 Array.prototype,而真数组的原型链中有 Array.prototype。因此伪数组没有数组的一般方法,比如 pop()、join() 等方法。例如我们经常通过DOM获取页面上具有相同属性的一系列元素, 此时得到的数据就是伪数组,我们可以通过

array = Array.from(arrayLike);

伪数组 或可遍历对象转换为真数组

数组元素添加与删除

方法 描述 备注
push() 向数组的最后面 插入一个或多个元素,返回结果为新数组的长度 会改变原数组
pop() 删除数组中的最后一个 元素,返回结果为被删除的元素 会改变原数组
unshift() 在数组最前面 插入一个或多个元素,返回结果为新数组的长度 会改变原数组
shift() 删除数组中的第一个 元素,返回结果为被删除的元素 会改变原数组
splice() 从数组中删除 指定的一个或多个元素,返回结果为被删除元素组成的新数组 会改变原数组
concat() 合并数组:连接两个或多个数组,返回结果为新的数组 不会改变原数组
fill() 填充数组:用固定的值填充数组,返回结果为新的数组 会改变原数组
push()

push():向数组的最后面插入一个或多个元素,返回结果为新数组的长度。会改变原数组,因为原数组变成了新数组

pop()

pop():删除数组中的最后一个元素,返回结果为被删除的元素

unshift()

在数组最前面插入一个或多个元素,返回结果为新数组的长度。会改变原数组,将原数组变成了新数组。插入元素后,其他元素的索引会依次调整。

shift()

shift():删除数组中的第一个元素,返回结果为被删除的元素。

arr1 = [1,"tom",{"name":"jack","age":12},[22,55]]
console.log(arr1.push(100)) // 5
console.log(arr1)  //[ 1, 'tom', { name: 'jack', age: 12 }, [ 22, 55 ], 100 ]
// pop():删除数组中的最后一个元素,返回结果为被删除的元素
console.log(arr1.pop()) // 100
console.log(arr1)  // [ 1, 'tom', { name: 'jack', age: 12 }, [ 22, 55 ] ]
//unshift():在数组最前面插入一个或多个元素,返回结果为新数组的长度。会改变原数组,将原数组变成了新数组。插入元素后,其他元素的索引会依次调整。
console.log(arr1.unshift(23,[34,56]))  // 6
console.log(arr1)   // [ 23, [ 34, 56 ], 1, 'tom', { name: 'jack', age: 12 }, [ 22, 55 ] ]
//shift():删除数组中的第一个元素,返回结果为被删除的元素。
console.log(arr1.shift() ) // 23
console.log(arr1)  // [ [ 34, 56 ], 1, 'tom', { name: 'jack', age: 12 }, [ 22, 55 ] ]
splice()

splice():从数组中删除指定的一个或多个元素,返回结果为被删除元素组成的新数组(会改变原来的数组)。该方法会改变原数组,会将指定元素从原数组中删除;被删除的元素会封装到一个新的数组中返回。

新数组 = 原数组.splice(起始索引index);
新数组 = 原数组.splice(起始索引index, 需要删除的个数);
新数组 = 原数组.splice(起始索引index, 需要删除的个数, 新的元素1, 新的元素2...);
上方语法中,第三个及之后的参数,表示:删除元素之后,向原数组中添加新的元素,这些元素将会自动插入到起始位置索引的前面。也可以理解成:删除了哪些元素,就在那些元素的所在位置补充新的内容。slice()方法和splice()方法很容易搞混,请一定要注意区分。

arr1 = [1,"tom",{"name":"jack","age":12},[22,55]]

var res = arr1.splice(1)
console.log(arr1)  // [1]
console.log(res)  //[ 'tom', { name: 'jack', age: 12 }, [ 22, 55 ] ]


arr1 = [1,"tom",{"name":"jack","age":12},[22,55]]

var res = arr1.splice(1,2) // //从第index为1的位置开始删除元素,一共删除三个元素
console.log(arr1)  // [ 1, [ 22, 55 ] ]
console.log(res)  // [ 'tom', { name: 'jack', age: 12 } ]


arr1 = [1,"tom",{"name":"jack","age":12},[22,55]]

var res = arr1.splice(1,2, "replase","replace","replace")
console.log(arr1)  // [ 1, 'replase', 'replace', 'replace', [ 22, 55 ] ]
console.log(res)  // [ 'tom', { name: 'jack', age: 12 } ]
concat()

concat():连接两个或多个数组,返回结果为新的数组 。不会改变原数组。concat()方法的作用是数组合并

    新数组 = 数组1.concat(数组2, 数组3 ...);
    //我们可以使用...这种扩展运算符,将两个数组进行合并
    const arr1 = [1, 2, 3];
	const result = ['a', 'b', 'c', ...arr1];
slice()

slice():从数组中提取 指定的一个或者多个元素,返回结果为新的数组(不会改变原来的数组)。

备注:该方法不会改变原数组,而是将截取到的元素封装到一个新数组中返回。

新数组 = 原数组.slice(开始位置的索引);
新数组 = 原数组.slice(开始位置的索引, 结束位置的索引);  //注意:提取的元素中,包含开始位置,不包含结束位置
fill()

fill():用一个固定值填充数组,返回结果为新的数组。会改变原数组。

// 用一个固定值填充数组。数组里的每个元素都会被这个固定值填充
新数组 = 数组.fill(固定值);

// 从 startIndex 开始的数组元素,用固定值填充
新数组 = 数组.fill(固定值, startIndex);

// 从 startIndex 到 endIndex 之间的元素(包左不包右),用固定值填充
新数组 = 数组.fill(固定值, startIndex, endIndex);

数组排序

方法 描述 备注
reverse() 反转数组,返回结果为反转后的数组 会改变原数组
sort() 对数组的元素,默认按照Unicode 编码,从小到大进行排序 会改变原数组
reverse()

reverse():反转数组,返回结果为反转后的数组(会改变原来的数组)。

var arr1 = [1,3,2,5,6]
arr1.reverse()
console.log(arr1) //  [ 6, 5, 2, 3, 1 ]
sort()

sort():对数组的元素进行从小到大来排序(会改变原来的数组)。

var arr1 = [1,3,12,5,6]
arr1.sort()
console.log(arr1) //  [ 1, 12, 3, 5, 6 ]

上述排序大家肯定有疑惑, 为什么12 排在3的前面,这是因为sort()方法是按照Unicode 编码进行排序的。要想让数组里面的数据按照我们想的排序 我们需要在sort里面定义参数

如果在 sort()方法中带参,我们就可以自定义排序规则。具体做法如下:

我们可以在 sort()的参数中添加一个回调函数,来指定排序规则。回调函数中需要定义两个形参,JS将会分别使用数组中的元素作为实参去调用回调函数。

JS根据回调函数的返回值来决定元素的排序:(重要)

  • 如果返回一个大于 0 的值,则元素会交换位置

  • 如果返回一个小于 0 的值,则不交换位置

  • 如果返回一个等于 0 的值,则认为两个元素相等,则不交换位置

    var arr1 = [1,3,12,5,6]
    arr1.sort(function (a, b) {
    return a - b;

    })
    console.log(arr1) // [ 1, 3, 5, 6, 12 ]
    //跟简单写法
    arr.sort((a, b) => a - b);

下面看一个复杂的例子

var arr1 = [{'age':2,'score':34},{'age':12,'score':24},{'age':5,'score':63},{'age':21,'score':87}]
arr1.sort(function (a, b) {
    return a.age - b.age;
    
})
console.log(arr1) 
// [
//     { age: 2, score: 34 },
//     { age: 5, score: 63 },
//     { age: 12, score: 24 },
//     { age: 21, score: 87 }
//   ]

查找元素

方法 描述 备注
indexOf(value) 从前往后索引,检索一个数组中是否含有指定的元素
lastIndexOf(value) 从后往前索引,检索一个数组中是否含有指定的元素
includes(item) 数组中是否包含指定的内容
find(function()) 找出第一个满足「指定条件返回 true」的元素
findIndex(function()) 找出第一个满足「指定条件返回 true」的元素的 index
every() 确保数组中的每个元素都满足「指定条件返回 true」,则停止遍历,此方法才返回 true 全真才为真。要求每一项都返回 true,最终的结果才返回 true
some() 数组中只要有一个元素满足「指定条件返回 true」,则停止遍历,此方法就返回 true 一真即真。只要有一项返回 true,最终的结果就返回 true
indexOf()/lastIndexOf():获取元素的索引
索引值 = 数组.indexOf(想要查找的元素, [查找的起始位置]);

元素的索引 = 数组.lastIndexOf(想要查询的元素);

indexOf() 是从左往右查找元素的位置。同理,lastIndexOf()是从右往左寻找。

解释 :可以检索一个数组中是否含有指定的元素。如果数组中含有该元素,则会返回其第一次出现的索引,并立即停止查找;如果没有找到指定的内容,则返回 -1。

这个方法的作用:

  • 如果找到了指定的元素,就返回元素对应的位置。
  • 如果没有找到指定的元素,就会返回-1。
includes()

判断一个数组中是否包含指定的元素。如果是,则会返回 true;否则返回 false。

布尔值 = arr.includes(想要查找的元素, [position]);

参数中的 position:如果不指定,则默认为0;如果指定,则规定了检索的起始位置。

find()

找出第一个满足「指定条件返回 true」的元素,并立即停止查找;如果没找到,则返回 undefined。

备注:一旦找到符合条件的第一个元素,将不再继续往下遍历。

const itemResult = arr.find((currentItem, currentIndex, currentArray) => {
    return true;
});

var arr1 = [23,"tom",{"name":"jack",'age':12},[23,56], '22']
var res = arr1.find((item, index)=>{
    if (typeof(item) == 'object') { //找到是对象的元素打印出来
        console.log(item)  
    }
    
});

// { name: 'jack', age: 12 }
// [ 23, 56 ]
findIndex()

找出第一个满足「指定条件返回 true」的元素的索引,并立即停止遍历;如果没找到,则返回 -1。

const indexResult = arr.findIndex((currentItem, currentIndex, currentArray) => {
    return true;
});

var arr1 = [23,"tom",{"name":"jack",'age':12},[23,56], '22']
var res = arr1.findIndex((item, index)=>{
    if (typeof(item) == 'object') {
        return 1; 
    }
    
});
console.log(res) // 2
every()

对数组中每一项运行回调函数,如果都返回 true,every 就返回 true;如果有一项返回 false,则停止遍历,此方法返回 false。

注意:every()方法的返回值是 boolean 值,参数是回调函数。

const boolResult = arr.every((currentItem, currentIndex, currentArray) => {
    return true;
});
some()

对数组中每一个元素运行回调函数,只要有一个元素返回 true,则停止遍历,此方法返回 true。

注意:some()方法的返回值是 boolean 值。

var arr1 = [23,"tom",{"name":"jack",'age':12},[23,56], '22']
var res = arr1.every((item, index)=>{
    if (item.length >2) {
        return 0; 
    }
    return 1;
    
});
console.log(res) // false

var arr1 = [23,"tom",{"name":"jack",'age':12},[23,56], '22']
var res = arr1.some((item, index)=>{
    if (item.length >2) {
        return 0; 
    }
    return 1;
    
});
console.log(res) // true

every() 和 some() 这两个方法,初学者很容易搞混。要怎么区分呢?你可以这样记:

  • every():全部真,才为真。当你需要让数组中的每一个元素都满足指定条件时,那就使用 every()。
  • some():一个真,则为真,点到为止。数组中只要有一个元素满足指定条件时,就停止遍历。那就使用 some()。

遍历数组

方法 描述 备注
for 循环 最传统的方式遍历数组,这个大家都懂
forEach() 遍历数组,但需要兼容 IE8 以上 不会改变原数组。forEach() 没有返回值。也就是说,它的返回值是 undefined
for of 遍历数组(ES6语法) 不会改变原数组。另外,不要使用 for in 遍历数组
map() 对原数组中的每一项进行加工,将组成新的数组 不会改变原数组
filter() 过滤数组:返回结果是 true 的项,将组成新的数组,返回结果为新的数组 不会改变原数组
reduce 接收一个函数作为累加器,返回值是回调函数累计处理的结果 比较复杂

获取并操作数组中的每一个元素,然后得到想要的返回结果。在实战开发中使用得非常频繁。

for循环遍历
var arr1 = [23,"tom",{"name":"jack",'age':12},[23,56], '22']
for (let index = 0; index < arr1.length; index++) {
    const element = arr1[index];
    console.log(element)
    
}
forEach遍历
// ES5语法
arr.forEach(function (currentItem, currentIndex, currentArray) {
	console.log(currentValue);
});

// ES6语法
arr.forEach((currentItem, currentIndex, currentArray) => {
	console.log(currentValue);
});

forEach()方法需要一个函数作为参数。这种函数,是由我们创建但是不由我们调用的,我们称为回调函数。

数组中有几个元素,该回调函数就会执行几次。

回调函数中传递三个参数:

  • 参数1:当前正在遍历的元素
  • 参数2:当前正在遍历的元素的索引
  • 参数3:正在遍历的数组

注意,forEach() 没有返回值。也可以理解成:forEach() 的返回值是 undefined。如果你尝试 newArray = currentArray.forEach()这种方式来接收,是达不到效果的。

var arr1 = [23,"tom",{"name":"jack",'age':12},[23,56], '22']
arr1.forEach((item,index)=> {
    console.log(item)
})
for of 遍历
for(let value of arr) {
	console.log(value);
}
map()
// ES5语法
const newArr =  arr.map(function (currentItem, currentIndex, currentArray) {
    return newItem;
});

// ES6语法
const newArr = arr.map((currentItem, currentIndex, currentArray) => {
    return newItem;
});

对数组中每一项运行回调函数,返回该函数的结果,组成的新数组(返回的是加工后的新数组)。不会改变原数组。作用:对数组中的每一项进行加工。

const arr1 = [1, 3, 6, 2, 5, 6];
const arr2 = arr1.map(item => {
  return item + 10; //让arr1中的每个元素加10
});
console.log(arr2); // 数组 arr2 的值:[11, 13, 16, 12, 15, 16]
filter()
const newArr = arr.filter((currentItem, currentIndex, currentArray) => {
    return true;
});

对数组中的每一项运行回调函数,该函数返回结果是 true 的项,将组成新的数组(返回值就是这个新数组)。不会改变原数组。作用:对数组进行过滤。

let arr1 = [1, 3, 6, 2, 5, 6];

let arr2 = arr1.filter(item => {
    if (item > 4) {
        return true; // 将arr1中大于4的元素返回,组成新的数组
    }
    return false;
});

console.log(JSON.stringify(arr1)); // 打印结果:[1,3,6,2,5,6]
console.log(JSON.stringify(arr2)); // 打印结果:[6,5,6]
reduce()

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。返回值是回调函数累计处理的结果。

语法

arr.reduce(function (previousValue, currentValue, currentIndex, arr) {}, initialValue);

参数解释:

  • previousValue:必填,上一次调用回调函数时的返回值
  • currentValue:必填,当前正在处理的数组元素
  • currentIndex:选填,当前正在处理的数组元素下标
  • arr:选填,调用 reduce()方法的数组
  • initialValue:选填,可选的初始值(作为第一次调用回调函数时传给 previousValue 的值)

在以往的数组方法中,匿名的回调函数里是传三个参数:item、index、arr。但是在 reduce() 方法中,前面多传了一个参数previousValue,这个参数的意思是上一次调用回调函数时的返回值。第一次执行回调函数时,previousValue 没有值怎么办?可以用 initialValue 参数传给它。

备注:绝大多数人在一开始接触 reduce() 的时候会很懵逼,但是没关系,有事没事多看几遍,自然就掌握了。如果能熟练使用 reduce() 的用法,将能替代很多其他的数组方法,并逐渐走上进阶之路,领先于他人。

let arr1 = [1, 2, 3, 4, 5, 6];

arr1.reduce((prev, item) => {
    console.log(prev);
    console.log(item);
    console.log('------');
    return 88;
}, 0);

打印结果:

0
1
------
88
2
------
88
3
------
88
4
------
88
5
------
88
6
------

上面的代码中,由于return的是固定值,所以 prev 打印的也是固定值(只有初始值是 0,剩下的遍历中,都是打印 88)。

现在来升级一下,实际开发中,prev 的值往往是动态变化的,这便是 reduce()的精妙之处。我们来看几个例子就明白了。

相关推荐
青灯文案12 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_748254886 分钟前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.18 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营22 分钟前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css
joan_851 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
还是大剑师兰特1 小时前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
m0_748236111 小时前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
Watermelo6172 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript