js的普通数组
在JavaScript中,普通数组(也称为原生数组或标准数组)是通过Array构造函数或数组字面量语法创建的。这些数组拥有Array.prototype上的所有方法和属性,使得它们能够方便地进行各种数组操作。
构造函数构造数组,普通数组的构造函数是Array
let array = new Array(1, 2, 3);
对象字面量构造数组
let array = [1, 2, 3];
我们来聊聊普通数组常用方法
可变方法
这些方法会直接修改原数组。
push():向数组的末尾添加一个或多个元素,并返回新的数组长度。pop():移除数组的最后一个元素,并返回该元素(数组长度减 1)。shift():移除数组的第一个元素,并返回该元素(数组长度减 1),同时数组中的其他元素前移一位。unshift():在数组的开头添加一个或多个元素,并返回新的数组长度,同时原数组中的元素相应后移。splice():通过删除或替换现有元素或添加新元素来修改数组,并返回被删除的元素数组。sort():对数组的元素进行排序,并返回数组。默认情况下,元素会被转换为字符串并按照字典序进行排序。reverse():反转数组中的元素顺序,并返回数组。
不可变方法
这些方法不会修改原数组,而是返回一个新的数组。
slice():返回一个新的数组对象,这一对象是一个浅拷贝,包含从begin(包括 begin)到end(不包括 end)的原数组中的部分元素。原数组不会被修改。concat():用于合并两个或多个数组。此方法不会改变现有数组,而是返回一个新数组。join():将数组的所有元素连接成一个字符串,元素之间用指定的分隔符进行分隔。如果不提供分隔符,则默认使用逗号(,)作为分隔符。toString():返回数组的字符串表示,该字符串由数组中的每个元素的toString()返回值经调用join方法连接(以逗号分隔)而成。indexOf():返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回 -1。lastIndexOf():返回在数组中可以找到一个给定元素的最后一个索引,如果不存在,则返回 -1。every():测试数组的所有元素是否都通过了被提供的测试函数。它返回一个布尔值。some():测试数组中是否至少有一个元素通过了被提供的测试函数。它返回一个布尔值。filter():创建一个新数组,其包含通过所提供函数实现的测试的所有元素。map():创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。reduce()和reduceRight():对数组中的每个元素(从左到右或从右到左)执行一个由您提供的 reducer 函数(升序或降序执行),将其结果汇总为单个返回值。forEach():对数组的每个元素执行一次提供的函数。
js的类数组
类数组对象(Array-like objects)是指那些具有 length 属性和索引属性的对象,但它们并不是真正的数组。常见的类数组对象包括 arguments 对象、DOM 方法返回的 NodeList 和 HTMLCollection 等。尽管这些对象看起来像数组,但它们并没有数组的所有方法。为了在类数组对象上使用数组的方法,通常需要将它们转换为真正的数组。
以下是一些常用的数组方法,以及如何在类数组对象上使用这些方法:
1. Array.prototype.slice.call()
- 用途:将类数组对象转换为真正的数组。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = Array.prototype.slice.call(arrayLike); console.log(array); // 输出: ['a', 'b', 'c']
2. Array.from()
- 用途:从类数组或可迭代对象创建一个新的数组实例。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = Array.from(arrayLike); console.log(array); // 输出: ['a', 'b', 'c']
3. Array.prototype.forEach.call()
- 用途:遍历类数组对象中的每个元素。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; Array.prototype.forEach.call(arrayLike, (item, index) => { console.log(`Index: ${index}, Value: ${item}`); }); // 输出: // Index: 0, Value: a // Index: 1, Value: b // Index: 2, Value: c
4. Array.prototype.map.call()
- 用途:对类数组对象中的每个元素应用一个函数,并返回一个新的数组。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const newArray = Array.prototype.map.call(arrayLike, (item, index) => { return item.toUpperCase(); }); console.log(newArray); // 输出: ['A', 'B', 'C']
5. Array.prototype.filter.call()
- 用途:过滤类数组对象中的元素,返回一个新的数组。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const filteredArray = Array.prototype.filter.call(arrayLike, (item, index) => { return item > 'a'; }); console.log(filteredArray); // 输出: ['b', 'c']
6. Array.prototype.reduce.call()
- 用途:对类数组对象中的每个元素执行一个累加器函数,将其结果汇总为单个值。
- 示例:
const arrayLike = { 0: 1, 1: 2, 2: 3, length: 3 }; const sum = Array.prototype.reduce.call(arrayLike, (acc, item) => { return acc + item; }, 0); console.log(sum); // 输出: 6
7. Array.prototype.find.call()
- 用途:查找类数组对象中满足条件的第一个元素。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const foundItem = Array.prototype.find.call(arrayLike, (item) => { return item === 'b'; }); console.log(foundItem); // 输出: 'b'
8. Array.prototype.findIndex.call()
- 用途:查找类数组对象中满足条件的第一个元素的索引。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const foundIndex = Array.prototype.findIndex.call(arrayLike, (item) => { return item === 'b'; }); console.log(foundIndex); // 输出: 1
9. Array.prototype.some.call()
- 用途:检查类数组对象中是否有至少一个元素满足条件。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const hasB = Array.prototype.some.call(arrayLike, (item) => { return item === 'b'; }); console.log(hasB); // 输出: true
10. Array.prototype.every.call()
- 用途:检查类数组对象中的所有元素是否都满足条件。
- 示例:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const allLowercase = Array.prototype.every.call(arrayLike, (item) => { return item === item.toLowerCase(); }); console.log(allLowercase); // 输出: true
我们来聊聊类数组常用的数组对象
类数组(Array-like objects)是指那些具有 length 属性和索引属性的对象,但它们并不是真正的 JavaScript 数组。这些对象看起来像数组,因为它们可以通过索引来访问元素,并且有一个 length 属性来表示元素的数量,但它们缺少数组的内置方法(如 push, pop, map, filter 等)。
常见的类数组对象
-
arguments 对象:
- 在函数内部,
arguments是一个类数组对象,它包含了传递给函数的所有参数。
function example() { console.log(arguments); // 类数组对象 console.log(arguments.length); // 参数数量 console.log(arguments[0]); // 第一个参数 } example(1, 2, 3); - 在函数内部,
-
DOM 方法返回的结果:
- 例如,
NodeList和HTMLCollection都是类数组对象。
const divs = document.getElementsByTagName('div'); console.log(divs); // HTMLCollection console.log(divs.length); // 元素数量 console.log(divs[0]); // 第一个元素 - 例如,
-
字符串:
- 字符串也可以被视为类数组对象,因为它们有
length属性,并且可以使用索引访问字符。
const str = 'hello'; console.log(str.length); // 5 console.log(str[0]); // 'h' - 字符串也可以被视为类数组对象,因为它们有
-
其他自定义对象:
- 任何具有
length属性和索引属性的对象都可以被视为类数组对象。
const obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; console.log(obj.length); // 3 console.log(obj[0]); // 'a' - 任何具有
如何处理类数组对象
由于类数组对象缺乏数组的方法,你通常需要将它们转换为真正的数组,以便使用数组的方法。以下是一些常见的方法:
-
使用
Array.prototype.slice.call():const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = Array.prototype.slice.call(arrayLike); console.log(array); // ['a', 'b', 'c'] -
使用
Array.from():const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = Array.from(arrayLike); console.log(array); // ['a', 'b', 'c'] -
使用扩展运算符
...:const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = [...arrayLike]; console.log(array); // ['a', 'b', 'c'] -
使用
Array.prototype.concat.apply():const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = Array.prototype.concat.apply([], arrayLike); console.log(array); // ['a', 'b', 'c']
区别
类数组(Array-like objects)和普通数组(Arrays)在JavaScript中有一些重要的区别。理解这些区别对于正确处理不同类型的对象非常重要。以下是它们之间的主要区别:
1. 定义和结构
-
普通数组:
- 普通数组是通过
Array构造函数或数组字面量创建的。 - 具有固定的结构,包含
length属性和索引属性,并且支持所有数组的方法(如push,pop,map,filter等)。 - 例如:
const arr = [1, 2, 3];
- 普通数组是通过
-
类数组:
- 类数组不是通过
Array构造函数创建的,但具有length属性和索引属性。 - 缺少数组的所有内置方法,不能直接使用数组的方法。
- 例如:
arguments对象、DOM 方法返回的NodeList和HTMLCollection。
- 类数组不是通过
2. 内置方法
-
普通数组:
- 支持所有数组的内置方法,如
push,pop,shift,unshift,splice,slice,map,filter,reduce,forEach等。 - 例如:
const arr = [1, 2, 3]; arr.push(4); // [1, 2, 3, 4]
- 支持所有数组的内置方法,如
-
类数组:
- 不支持数组的内置方法,因为它们不是真正的数组实例。
- 例如:
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; // arrayLike.push('d'); // TypeError: arrayLike.push is not a function
3. 使用场景
-
普通数组:
- 用于存储和操作一组有序的数据。
- 适用于需要频繁增删元素和使用数组方法的场景。
-
类数组:
- 常见于函数内部的
arguments对象。 - DOM 操作中,如
document.querySelectorAll返回的NodeList或document.getElementsByTagName返回的HTMLCollection。 - 一些自定义的对象,可能出于性能或其他原因被设计为类数组。
- 常见于函数内部的
4. 转换为普通数组
- 类数组转换为普通数组:
- 可以使用多种方法将类数组转换为普通数组,以便使用数组的方法。
- 例如:
- 使用
Array.prototype.slice.call():const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = Array.prototype.slice.call(arrayLike); console.log(array); // ['a', 'b', 'c'] - 使用
Array.from():const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = Array.from(arrayLike); console.log(array); // ['a', 'b', 'c'] - 使用扩展运算符
...:const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; const array = [...arrayLike]; console.log(array); // ['a', 'b', 'c']
- 使用
5. 性能考虑
-
普通数组:
- 由于内置了大量方法,使用起来非常方便,但在某些情况下可能会比类数组更消耗资源。
-
类数组:
- 通常是为了性能优化而设计的,避免了数组方法的额外开销。
- 例如,
NodeList和HTMLCollection是实时更新的,这意味着它们会自动反映 DOM 的变化,而不需要重新获取。
-
普通数组:是通过
Array构造函数或数组字面量创建的,支持所有数组的内置方法,适用于需要频繁操作数据的场景。 -
类数组:具有
length属性和索引属性,但缺少数组的内置方法,常见于arguments对象和 DOM 操作中,可以通过多种方法转换为普通数组。
。