前言
数组是编程中非常基础且广泛使用的数据结构,用于按顺序存储多个值,是一种用于存储多个值的有序集合,常用于:
无论是处理用户输入、管理商品列表还是实现算法,数组都扮演着重要角色。
那这篇文章将带你走进数组的世界,理解它们是如何工作的。好我们一起来看看吧。
JS 数组基础
1. 数组的声明和初始化
声明数组有 2 种方式。
var numbers = [1, 2, 3, 4, 5]
var numbers = new Array(1, 2, 3, 4, 5)
这两种方式都可以创建数组,但推荐使用第一种方式,简单,高效。
2. 元素存储和索引
数组的每个元素都存储在一个位置上,称为索引,索引从 0
开始。
console.log(numbers[0]) // 输出: 1
console.log(numbers[numbers.length - 1]) // 输出最后一个元素
3. 数组的长度和空元素
数组的长度可以通过 length
属性获取,数组可以包含空元素。
console.log(numbers.length) // 输出: 5
var emptyArray = new Array(3) // 创建一个包含3个空元素的数组
4. 多维数组与嵌套数组
JavaScript 支持多维数组,即数组中的元素也可以是数组。
var matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
JS 数组类型
在 JavaScript 中,数组是一种灵活的数据结构,可以存储任何类型的数据。这包括但不限于以下几种数据类型:
数字(Number):可以存储整数或浮点数。
var numbers = [1, 2, 3, 4.5]
字符串(String):可以存储文本。
var names = ['Alice', 'Bob', 'Carol', ''] // 最后一个空文本也可以
布尔值(Boolean):可以存储逻辑值 true
或 false
。
var flags = [true, false, true]
对象(Object):可以存储对象或对象的集合。
var users = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 }
]
数组(Array):数组中可以包含数组,形成嵌套数组或多维数组。
var matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
函数(Function):数组可以存储函数,使得数组可以用于回调和高阶函数。
var actions = [
function () {
console.log('Action 1')
},
function () {
console.log('Action 2')
}
]
null 和 undefined:数组也可以包含 null
或 undefined
值。
var mixedArray = [1, null, 'string', undefined, 5]
Symbol:虽然不常见,但数组也可以存储 Symbol
类型的值。
var symbols = [Symbol('a'), Symbol('b')]
由于 JavaScript 是一种动态类型语言,数组中可以混合使用不同类型的数据,这为数据存储和处理提供了极大的灵活性。
然而,这也意味着在处理数组时需要小心,尤其是在执行类型敏感的操作时,如排序或数学计算。
JS 数组操作
以下我整理了 18 个常用的数组操作。
1. 数组添加、删除元素
在 JavaScript 中,push()
、pop()
、shift()
和 unshift()
是数组对象的内置方法,用于在数组的两端添加或删除元素。
push()
和 pop()
分别用于在数组末尾添加元素和删除数组末尾的元素。shift()
和 unshift()
分别用于删除数组的第一个元素和在数组开头添加元素。
1)push()
方法用于在数组的末尾添加一个或多个元素,并返回数组的新长度。
语法如下:
array.push(element1, element2, ..., elementN);
返回值: 新的数组长度。
var fruits = ['Apple', 'Banana']
fruits.push('Orange') // 在末尾添加 "Orange"
console.log(fruits) // ["Apple", "Banana", "Orange"]
console.log(fruits.length) // 3
2)pop()
方法用于删除数组的最后一个元素,并返回被删除的元素。如果数组为空,则返回 undefined
。
语法如下:
array.pop()
返回值: 被删除的元素。代码如下。
var fruits = ['Apple', 'Banana', 'Orange']
var removed = fruits.pop() // 删除并返回最后一个元素 "Orange"
console.log(removed) // "Orange"
console.log(fruits) // ["Apple", "Banana"]
3)shift()
方法用于删除数组的第一个元素,并返回被删除的元素。如果数组为空,则返回 undefined
。
语法如下:
array.shift()
返回值: 被删除的元素。
var fruits = ['Apple', 'Banana', 'Orange']
var removed = fruits.shift() // 删除并返回第一个元素 "Apple"
console.log(removed) // "Apple"
console.log(fruits) // ["Banana", "Orange"]
4)unshift()
方法用于在数组的开头添加一个或多个元素,并返回数组的新长度。
语法如下:
array.unshift(element1, element2, ..., elementN);
返回值: 新的数组长度。
var fruits = ['Banana', 'Orange']
fruits.unshift('Apple') // 在开头添加 "Apple"
console.log(fruits) // ["Apple", "Banana", "Orange"]
console.log(fruits.length) // 3
这些方法都是修改原数组的,而不是创建一个新的数组。它们常用于实现栈和队列的逻辑,例如,push()
和 pop()
常用于栈操作,而 unshift()
和 shift()
常用于队列操作。
2. 数组元素的查找
在 JavaScript 中,indexOf()
、find()
和 findIndex()
是数组对象的内置方法,用于搜索数组中的元素,并根据搜索结果返回特定的值。
1)indexOf()
方法用于查找元素在数组中的索引位置。它使用相当高频。它会从数组的开头(默认)或指定的索引位置开始搜索,并返回找到的第一个匹配元素的索引。如果找不到元素,则返回 -1
。
语法:
array.indexOf(searchElement, fromIndex)
fromIndex
(可选):开始搜索的起始索引,默认为 0
。
返回值: 找到的索引位置或 -1
。
var fruits = ['Apple', 'Banana', 'Mango', 'Apple']
var index = fruits.indexOf('Mango') // 返回: 2
console.log(index) // 输出: 2
index = fruits.indexOf('Cherry') // 返回: -1,因为 "Cherry" 不在数组中
console.log(index) // 输出: -1
2)find()
是 JavaScript 数组的一个内置方法,用于查找符合特定条件的第一个元素。find()
方法与 filter()
方法类似,但它只返回符合条件的第一个元素,而不是所有符合条件的元素组成的数组。
语法如下:
array.find(callback(element, index, array), thisArg);
callback
:用于测试数组中每个元素的函数。是 find()
方法的核心,它定义了用于测试数组元素的条件。callback
函数对于数组中的每个元素执行一次,直到找到一个使 callback
返回 true
的元素。一旦找到这样的元素,find()
就会停止搜索并返回该元素。它接收以下参数:array
(可选):find()
方法正在操作的数组。
thisArg
(可选):执行回调时,用作 this
的值。
返回值:find()
方法返回数组中符合条件的第一个元素。如果没有符合条件的元素,则返回 undefined
。
来个案例,假设我们有一个用户数组,我们想要找到第一个年龄大于 30 岁的用户:
var users = [
{ name: "John", age: 29 },
{ name: "Jane", age: 31 },
{ name: "Mark", age: 26 }
];
var user = users.find(function(user) {
return user.age > 30;
});
console.log(user); // 输出: { name: "Jane", age: 31 }
在这个例子中,find()
方法遍历 users
数组,callback
函数检查每个用户的年龄是否大于 30。找到第一个符合条件的用户(Jane)后,find()
返回该用户对象。
find()
方法非常适合用于需要基于某个条件从数组中检索单个元素的场景。
3)findIndex()
是 JavaScript 数组的一个内置方法,它与 find()
方法类似,但 findIndex()
返回的是数组中符合条件的第一个元素的索引,而不是元素本身。
语法如下:
array.findIndex(callback(element, index, array), thisArg);
callback
:用于测试数组中每个元素的函数。它接收以下参数:array
(可选):findIndex()
方法正在操作的数组。
thisArg
(可选):执行回调时,用作 this
的值。
返回值:findIndex()
方法返回数组中符合条件的第一个元素的索引。如果没有符合条件的元素,则返回 -1
。
来个案例,假设我们有一个用户数组,我们想要找到第一个年龄大于 30 岁的用户的索引:
var users = [
{ name: "John", age: 29 },
{ name: "Jane", age: 31 },
{ name: "Mark", age: 26 }
];
var index = users.findIndex(function(user) {
return user.age > 30;
});
console.log(index); // 输出: 1
在这个例子中,findIndex()
方法遍历 users
数组,callback
函数检查每个用户的年龄是否大于 30。找到第一个符合条件的用户(Jane)后,findIndex()
返回该用户在数组中的索引,即 1
。
findIndex()
方法非常适合用于需要基于某个条件从数组中检索元素的索引的场景。
例如,如果你需要删除或替换数组中的特定元素,你可以先使用 findIndex()
查找元素的索引,然后使用该索引进行操作。
3. 数组的截取与拷贝
slice()
方法:这是一个非常实用的方法,可以从一个现有的数组中取出具体的元素,并生成一个新的子数组,此过程并不会导致原数组发生改变。
语法:array.slice(start, end)
start
:(可选)从哪里开始选取。如果为负值,表示从数组末尾开始算起的位置。默认为 0。end
:(可选)在这个位置停止选取(不包括它本身)。如果省略,表示选取到数组末尾。如果为负数,表示从数组末尾开始算起的位置。
示例:
var fruits = ['apple', 'banana', 'cherry', 'date']
var citrus = fruits.slice(1, 3)
console.log(citrus) // 输出: ['banana', 'cherry']
console.log(fruits) // 输出: ['apple', 'banana', 'cherry', 'date']
4. 数字的添加,替换,删除
splice()
方法:这个方法作用于数组,用于添加、替换或删除数组的元素,并返回被修改的元素。此操作会改变原数组。
语法:array.splice(index, howmany, item1, ....., itemX)
howmany
:要删除的元素个数。如果设置为 0,则不会删除元素。item1, ..., itemX
:待添加到数组的元素。
示例:
var fruits = ['apple', 'banana', 'cherry', 'date']
var removed = fruits.splice(1, 2, 'kiwi', 'mango')
console.log(removed) // 输出:['banana', 'cherry']
console.log(fruits) // 输出:['apple', 'kiwi', 'mango', 'date']
5. 数组元素的遍历
1)forEach()
:该方法用于遍历数组的每一个元素,并对每一个元素执行一次提供的函数。
语法:arr.forEach(callback(element, index, array), thisArg)
thisArg
:执行回调时用作 this 的对象。
示例:
array1.forEach(function (element, index) {
console.log(index, element)
})
// 输出: 0 'a'
// 输出: 1 'b'
// 输出: 2 'c'
2) map()
:该方法通过调用函数对每个元素进行处理并返回处理后的新数组,原数组不会改变。
语法:var newArr = oldArray.map(callback(element, index, array), thisArg)
thisArg
:执行回调时用作 this 的对象。
代码如下:
var squares = numbers.map(function (num) {
return num ** 2
})
console.log(squares) // 输出: [1, 4, 9, 16]
6. 数组的过滤
filter()
是数组对象的一个内置方法,用于创建一个新数组,包含通过所提供函数实现的测试的所有元素。
语法如下:
array.filter(callback(element, index, array), thisArg);
callback
:用于测试数组中每个元素的函数。它接收当前元素作为第一个参数,元素的索引作为第二个参数,调用 filter
的数组作为第三个参数。thisArg
(可选):执行回调时,用作 this
的值。
返回值:filter()
方法返回一个新数组,包含通过 callback
函数测试的元素。
还需要了解的是,以下几点:
- 遍历数组的每个元素,
callback
函数为每个元素执行一次。 - 如果
callback
函数对于某个元素返回 true
,则该元素会被包含在返回的新数组中。 callback
函数不执行数组中被跳过的元素(例如,通过 filter()
或 forEach()
中的 return false
)。- 如果
callback
函数始终返回 false
,则返回一个空数组。
来看下代码:
var evenNumbers = numbers.filter(function (item) {
return item % 2 == 0
}) // 筛选出偶数
console.log(evenNumbers) // 输出:[2, 4, 6]
在这个示例中,我们有一个包含六个项的数组 numbers
。然后,我们调用了 filter()
方法,传入了一个回调函数,检查数组中的每个数字是否为偶数。filter()
方法返回一个新的数组 evenNumbers
,这个新数组仅包含 numbers
中的偶数。
再来一个数组对象的案例。
var users = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Carol', age: 22 }
]
var usersOver24 = users.filter(function (user) {
return user.age > 26
})
console.log(usersOver24) // 输出: [{ name: "Bob", age: 30 }]
在上面这个例子中,我们过滤出所有年龄超过 24 岁的用户。
filter()
方法非常有用,特别是当你需要根据某些条件从数组中提取元素时。它返回的新数组使得原始数组保持不变,这有助于保持代码的可读性和可维护性。
7. 数组排序
sort()
:该方法用于对数组元素进行排序,会改变原数组。
语法:arr.sort([compareFunction])
compareFunction
:(可选)用来确定数组的排序顺序。
好,我们来看下代码。
var numbers = [20, 3, 25, 100]
numbers.sort()
console.log(numbers) // 如果没有写排序规则输出: [100, 20, 25, 3],结果明显不对
打印结果,我们发现,不对,25 竟然比 100 还大,3 竟然是最大的,如图。![](http://image109.360doc.com/DownloadImg/2024/05/0813/283366555_1_20240508013318447.png)
为什么呢?原因就是,在 JavaScript 中,sort()
方法默认对数组元素进行排序,但它的比较逻辑是基于元素的字符串形式的字典顺序,而不是元素的原始数值顺序。这意味着,如果没有提供自定义的比较函数,sort()
方法会将所有元素转换为字符串,然后比较它们的 UTF-16 码点值。
对于数字,它们的字符串形式是按照它们在字符集中的顺序排序的,这通常与数值顺序不一致。例如,字符串 "10" 在字典顺序上排在 "2" 之前,因为 "1" 的码点值小于 "2"。
所以,按照字典顺序排序。结果是 [100, 20, 25, 3]
,这显然不是我们期望的数值顺序。
为了修复这个问题,我们应该提供一个自定义的比较函数给 sort()
方法,这样它就可以按照数值大小进行排序,而不是字典顺序。
var numbers = [20, 3, 25, 100]
numbers.sort(function (a, b) {
return a - b // 升序排序
// return a - b // 如果降序排序
})
console.log(numbers) // 输出: [3, 20, 25, 100]
在这个例子中,我们提供了一个比较函数,它接受两个参数 a
和 b
。如果 a
应该在 b
之前,我们返回一个负数;如果 a
等于 b
,我们返回 0
;如果 a
应该在 b
之后,我们返回一个正数。这样,sort()
方法就会按照数值的升序对数组进行排序。
8. 数组到字符串的转换
1)join()
:将数组转换为字符串。
该方法将数组(或一个类数组对象)的所有元素连接到一个字符串中,可以指定分隔符。
语法:str = arr.join([separator])
separator
:(可选)指定用于分隔数组中的元素的字符。
2)toString()
:将数组转换为字符串,是所有对象的通用方法,在数组中,以,作为默认分隔符。
看下代码。
var elements = ['Fire', 'Wind', 'Rain']
console.log(elements.join()) // 输出: 'Fire,Wind,Rain'
console.log(elements.join('')) // 输出: 'FireWindRain'
console.log(elements.join('-')) // 输出: 'Fire-Wind-Rain'
var stringWithBrackets = numbers.toString() // 输出: 'Fire-Wind-Rain'
它们的区别在于:
- 分隔符:
join()
允许你指定一个分隔符,而 toString()
不允许。 - 使用场景:
join()
更适合需要自定义分隔符的场景,而 toString()
更适合不需要分隔符的场景。 - 方法来源:
join()
是数组的专属方法,而 toString()
是所有对象的通用方法。
在实际应用中,选择使用 join()
还是 toString()
取决于你是否需要自定义分隔符以及你的具体需求。如果你需要一个简单的数组字符串表示,且不需要分隔符,toString()
是一个好选择。如果你需要更灵活地控制字符串的格式,那么 join()
会是更好的选择。
9. 字符串到数组的转换
split()
:将字符串分割成数组,通过指定分隔符。var words = 'one, two, three'.split(', ') // ["one", "two", "three"]
var lines = 'Line 1\nLine 2'.split('\n') // ["Line 1", "Line 2"]
10. 数组的反转
reverse()
:该方法对数组的元素进行反转,无需入参,使数组中的元素颠倒顺序,并返回结果数组。需要注意的是,该方法会改变原始数组。比如:
语法:arr.reverse()
var array1 = ['one', 'two', 'three']
array1.reverse()
console.log(array1) // 输出: [ 'three', 'two', 'one' ]
11. 数组的合并
concat()
:该方法用于合并两个或更多数组,并返回合并后的新数组,原数组不会改变。
语法:var newArr = oldArray.concat(value1, value2, ..., valueN)
valueN
:将被合并的值。如果是数组,则数组中的每一个元素都会被添加。
示例:
var array1 = ['a', 'b', 'c']
var array2 = ['d', 'e', 'f']
var array3 = array1.concat(array2)
console.log(array3) // 输出: ['a', 'b', 'c', 'd', 'e', 'f']算数组元素的和
这些方法很好用,但数组的方法不止这么多,后续呢,随着你学习,实践还会有其他属性,这里只是结合我项目实战,从高到低使用频次,列举了常用的。
用的时候,需要注意的是,在不同浏览器的兼容性。通过https:///来查询。在里面输入findIndex,如图。![](http://image109.360doc.com/DownloadImg/2024/05/0813/283366555_2_20240508013318603_wm.png)