JS数组如何创建和操作

javascript数组是前端开发中处理有序数据的核心工具,它通过数字索引存储元素,支持丰富的增删改查操作,而普通对象则用于存储键值对形式的结构化数据;在处理大量数据时,unshift、shift和splice等导致元素位移的操作可能引发性能问题,可通过优先使用push/pop、合并高阶函数调用或改用for循环来优化;数组还可模拟栈(用push/pop实现lifo)和队列(用push/shift实现fifo),并在异步编程中用于任务队列或结果收集,适用于需顺序处理的场景。

JS数组如何创建和操作

JavaScript数组是前端开发中非常核心的数据结构,它本质上是一种特殊的对象,用于存储有序的元素集合。理解它的创建和操作方式,是高效处理数据的基础。可以说,无论你是在处理用户列表、商品信息,还是复杂的图表数据,数组都无处不在,掌握它能让你在数据处理上如鱼得水。

解决方案

创建JavaScript数组的方法有好几种,我个人最常用也最推荐的是字面量方式,因为它简洁直观,出错的概率也小。

数组的创建:

数组字面量

[]

这是最常见也是我最推荐的方式。

const myArray = [1, 2, 3, 'hello', true]; // 包含不同类型元素的数组const emptyArray = []; // 空数组

这种方式非常直观,一眼就能看出它是一个数组,并且包含了哪些元素。

new Array()

构造函数:

const arr1 = new Array(); // 创建一个空数组,等同于 []const arr2 = new Array(5); // 创建一个长度为5的空数组,元素都是 undefinedconst arr3 = new Array(1, 2, 3); // 创建包含指定元素的数组,等同于 [1, 2, 3]

这里有个小陷阱,

new Array(5)

创建的是一个有5个空槽位的数组,而不是包含数字5的数组。如果你想创建只包含一个数字5的数组,你得写成

[5]

或者

new Array(5)

后面再

push(5)

,但那样就多此一举了。所以,我一般不太喜欢用

new Array()

来创建已知元素的数组,除非是需要预先指定长度的场景。

Array.of()

const arr4 = Array.of(1, 2, 3, 5); // [1, 2, 3, 5]const arr5 = Array.of(7); // [7]
Array.of()

解决了

new Array()

在处理单个数字参数时的歧义,无论参数是一个还是多个,它都会把这些参数作为数组的元素。我觉得这个方法挺有意思,但在实际项目中,字面量还是我的首选。

Array.from()

const str = "hello";const arrFromStr = Array.from(str); // ['h', 'e', 'l', 'l', 'o']const set = new Set([1, 2, 3]);const arrFromSet = Array.from(set); // [1, 2, 3]// 结合 map 函数const numbers = [1, 2, 3];const doubledNumbers = Array.from(numbers, x => x * 2); // [2, 4, 6]
Array.from()

是一个非常强大的方法,它可以从类数组对象(比如

arguments

对象、DOM

NodeList

)或可迭代对象(比如

Set

,

Map

,

String

)创建一个新的数组。当你需要把一个非数组的数据结构转换成数组,并且可能需要同时进行一些转换时,它就派上用场了。

数组的常见操作:

数组的操作方法非常丰富,覆盖了增、删、改、查、遍历等各个方面。

增加元素:

push()

:在数组末尾添加一个或多个元素,返回新数组的长度。

let arr = [1, 2];arr.push(3, 4); // arr 现在是 [1, 2, 3, 4]
unshift()

:在数组开头添加一个或多个元素,返回新数组的长度。

let arr = [3, 4];arr.unshift(1, 2); // arr 现在是 [1, 2, 3, 4]

需要注意的是,

unshift()

会改变所有元素的索引,在大数组上性能开销可能比较大。

删除元素:

pop()

:删除并返回数组的最后一个元素。

let arr = [1, 2, 3];let last = arr.pop(); // last 是 3, arr 现在是 [1, 2]
shift()

:删除并返回数组的第一个元素。

let arr = [1, 2, 3];let first = arr.shift(); // first 是 1, arr 现在是 [2, 3]

unshift()

类似,

shift()

也会引起索引变化,性能问题需要留意。

splice(start, deleteCount, ...items)

:这是一个非常灵活且强大的方法,可以删除、替换或添加元素。

let arr = [1, 2, 3, 4, 5];arr.splice(2, 1); // 从索引2开始删除1个元素,arr 现在是 [1, 2, 4, 5]arr.splice(1, 0, 'a', 'b'); // 在索引1处添加'a', 'b',不删除任何元素,arr 现在是 [1, 'a', 'b', 2, 4, 5]arr.splice(2, 2, 'x', 'y'); // 从索引2开始删除2个元素,然后添加'x', 'y',arr 现在是 [1, 'a', 'x', 'y', 4, 5]
splice()

真的很万能,但参数多的时候也容易搞混,我有时候会先在控制台试一下。

访问和修改元素:

通过索引:数组元素通过从0开始的索引访问。

let arr = ['apple', 'banana', 'orange'];console.log(arr[0]); // 'apple'arr[1] = 'grape'; // arr 现在是 ['apple', 'grape', 'orange']
length

属性:获取或设置数组的长度。

let arr = [1, 2, 3];console.log(arr.length); // 3arr.length = 2; // arr 现在是 [1, 2]arr.length = 5; // arr 现在是 [1, 2, undefined, undefined, undefined]

遍历数组:

forEach()

:遍历数组,对每个元素执行回调函数,没有返回值。

let arr = [1, 2, 3];arr.forEach(item => console.log(item * 2)); // 输出 2, 4, 6
map()

:遍历数组,对每个元素执行回调函数,并返回一个新数组,新数组的元素是回调函数的返回值。

let arr = [1, 2, 3];let newArr = arr.map(item => item * 2); // newArr 是 [2, 4, 6]
map()

非常适合做数据转换。

filter()

:遍历数组,对每个元素执行回调函数,返回一个新数组,新数组包含所有回调函数返回

true

的元素。

let arr = [1, 2, 3, 4, 5];let evenNumbers = arr.filter(item => item % 2 === 0); // evenNumbers 是 [2, 4]

数据筛选的利器。

reduce()

/

reduceRight()

:将数组元素“归约”成一个单一的值。

let arr = [1, 2, 3, 4];let sum = arr.reduce((acc, current) => acc + current, 0); // sum 是 10

这个方法非常强大,可以实现很多复杂的聚合操作。

for...of

循环:ES6 引入的遍历方式,更简洁,可以直接获取元素值。

let arr = ['a', 'b', 'c'];for (const item of arr) {    console.log(item); // 'a', 'b', 'c'}

我个人在不需要索引时,非常喜欢用

for...of

查找元素:

indexOf()

/

lastIndexOf()

:查找元素在数组中的第一个/最后一个索引,找不到返回 -1。

includes()

:判断数组是否包含某个元素,返回布尔值。

find()

/

findIndex()

:查找第一个满足条件的元素/其索引。

其他常用方法:

concat()

:连接两个或多个数组,返回一个新数组。

slice(start, end)

:截取数组的一部分,返回一个新数组,不改变原数组。

join(separator)

:将数组的所有元素连接成一个字符串。

reverse()

:反转数组元素顺序,改变原数组。

sort(compareFunction)

:对数组元素进行排序,改变原数组。排序默认按字符串Unicode编码,所以数字排序需要提供比较函数。

JavaScript数组与普通对象有什么区别,何时选择使用数组?

这问题问得挺好,很多人初学JS时会混淆数组和普通对象。最核心的区别在于它们的结构和用途

数组是有序的集合,它的元素通过数字索引来访问,索引从0开始递增。你可以把它想象成一排整齐的抽屉,每个抽屉都有一个编号,里面放着一个东西。数组的主要目的是存储列表型数据,比如一系列用户ID、一个月的销售额、一堆待办事项。它的内部实现通常会优化对连续内存区域的访问,使得按索引查找和迭代非常高效。

而普通对象(或称作字典、哈希表)是无序的键值对集合,它的键是字符串(或者Symbol),值可以是任何数据类型。你可以把它想象成一个档案柜,每个文件都有一个名字(键),里面装着相关的信息(值)。对象的主要目的是存储结构化数据,表示一个实体的属性,比如一个用户的姓名、年龄、地址等。

何时选择使用数组?

我通常会根据以下几个点来决定:

数据是否有序且同质性高? 如果你有一组数据,它们的顺序很重要,或者它们都属于同一类型(比如都是数字、都是字符串),那么数组是首选。例如,一个商品列表、一个用户评论流。需要频繁进行增删改查操作,且这些操作基于位置或顺序? 比如,你需要删除列表中的第N个元素,或者在列表末尾添加新项,数组的

push

,

pop

,

splice

等方法非常适合。需要遍历整个集合进行处理? 数组提供了丰富的迭代方法(

forEach

,

Map

,

filter

,

reduce

),这些方法专门为处理列表数据而设计,用起来非常方便。

何时选择使用对象?

反之,如果你的数据:

是结构化的,有明确的属性名? 比如,你需要表示一个人的信息:

{ name: '张三', age: 30, city: '北京' }

需要通过有意义的键来访问数据? 你想通过

user.name

而不是

user[0]

来获取姓名。数据的顺序不重要? 对象的属性顺序在ES2015后对于字符串键是保持插入顺序的,但从概念上讲,它不是一个“有序”的数据结构,你不会依赖它的索引。

说实话,有时候数组和对象也会混用,比如一个数组里装着多个对象:

[{ id: 1, name: 'A' }, { id: 2, name: 'B' }]

,这在前端数据处理中太常见了,它完美结合了数组的有序性和对象的结构化能力。

在处理大量数据时,JavaScript数组的哪些操作可能影响性能,如何优化?

处理大量数据时,JavaScript数组的性能确实是个需要考虑的问题。有些操作在小数组上几乎无感,但数据量一上去,就可能成为瓶颈。

我个人在实际开发中,最常遇到性能问题的操作主要有以下几种:

unshift()

shift()

这两个方法在数组头部添加或删除元素。它们的问题在于,每次操作都会导致数组中所有后续元素的索引发生变化。这意味着JavaScript引擎需要重新索引(或者说,移动)数组中所有现存的元素。如果数组有10000个元素,你

unshift

一个新元素,那么这10000个元素都需要被“挪动”一下,这个开销是线性的,也就是O(n)复杂度。

优化建议:如果可以,尽量使用

push()

pop()

在数组尾部操作,它们是O(1)复杂度,性能最好。如果必须在头部操作,并且数据量巨大且操作频繁,可以考虑使用双端队列(deque)的数据结构,或者用两个数组模拟一个队列,一个用于头部,一个用于尾部,或者在某些特定场景下,用对象来模拟稀疏数组。不过,对于大多数前端应用

shift

/

unshift

的性能问题只有在极端情况下才会显现。

splice()

的大量删除或插入:

splice()

方法非常强大,但也继承了

shift

/

unshift

的部分性能问题。当你在数组中间进行大量元素的删除或插入时,同样会导致后续元素的重新索引。比如,在一个10万个元素的数组中间删除5万个元素,那性能消耗是巨大的。

优化建议:尽量避免在大型数组的中间频繁使用

splice

进行大量元素的增删。如果需要删除多个元素,并且这些元素是连续的,

splice

仍然是合适的。如果是需要移除不符合条件的元素,可以考虑使用

filter()

方法。

filter()

会创建一个新数组,虽然也是遍历,但它避免了原地修改带来的索引移动开销。如果需要替换或更新大量元素,可以考虑先构建一个新数组,然后替换旧数组,而不是原地修改。

频繁的

map()

,

filter()

,

reduce()

等高阶函数链式调用:这些方法非常方便,可读性也很好。但它们都有一个共同点:每次调用都会遍历整个数组(或部分数组),并且

map()

filter()

还会创建新的数组。如果在一个大型数组上进行多次链式调用,例如

arr.filter(...).map(...).reduce(...)

,那么数组会被遍历多次,并且创建多个中间数组,这会增加内存开销和CPU时间。

优化建议:

合并操作: 尝试将多个操作合并到一个

reduce()

调用中,这样只需要遍历数组一次。

// 原始链式调用const result = largeArray.filter(item => item.isActive)                         .map(item => item.value * 2)                         .reduce((sum, val) => sum + val, 0);// 优化:使用 reduce 合并const optimizedResult = largeArray.reduce((acc, item) => {    if (item.isActive) {        acc += item.value * 2;    }    return acc;}, 0);

使用

for...of

或传统

for

循环: 在对性能要求极高的场景下,传统的

for

循环或 ES6 的

for...of

循环通常比高阶函数更快,因为它们避免了函数调用的开销和中间数组的创建。

let sum = 0;for (const item of largeArray) {    if (item.isActive) {        sum += item.value * 2;    }}

我个人觉得,对于绝大多数日常业务,高阶函数带来的可读性提升远大于其微小的性能损失,所以除非真的遇到性能瓶颈,否则我不会盲目地去用

for

循环替换它们。

不当的

sort()

使用:

sort()

方法会原地修改数组,并且其默认的排序是基于字符串的Unicode编码,这在排序数字时会导致意想不到的结果(比如

[1, 10, 2].sort()

可能会得到

[1, 10, 2]

[1, 2, 10]

,取决于JS引擎实现,但通常不是你想要的数值排序)。此外,

sort()

的性能通常是O(n log n),对于超大数组,仍然需要注意。

优化建议:提供比较函数: 始终为数字排序提供一个比较函数:

arr.sort((a, b) => a - b)

避免不必要的排序: 如果数据已经有序,或者只需要部分排序,不要对整个数组进行排序。考虑其他排序算法: 在极特殊且性能要求严苛的场景,可能需要手写或引入更适合特定数据分布的排序算法。

总的来说,优化数组操作性能的关键在于:减少不必要的遍历、避免频繁的元素移动(尤其是数组头部操作)、以及合理利用不同方法的特性。 实践中,通常是先写出可读性好的代码,只有在性能分析工具(如浏览器开发者工具的 Performance 面板)显示数组操作确实是瓶颈时,才考虑进行优化。

JavaScript数组在异步编程或特定数据结构(如栈、队列)中如何应用?

JavaScript数组的灵活性使得它不仅仅是一个简单的数据容器,它还能在更复杂的场景中发挥作用,尤其是在异步编程和模拟特定数据结构方面。

1. 模拟栈(Stack)和队列(Queue):

数组的

push

,

pop

,

shift

,

unshift

方法,简直就是为实现栈和队列量身定制的。

栈 (Stack) – 后进先出 (LIFO):栈的特点是最后进入的元素最先出来。这完美对应了数组的

push()

pop()

方法。

入栈 (Push): 使用

push()

将元素添加到数组末尾。

出栈 (Pop): 使用

pop()

从数组末尾移除元素。

class MyStack {constructor() {    this.items = [];}push(element) {    this.items.push(element);}pop() {    if (this.isEmpty()) {        return "Stack is empty";    }    return this.items.pop();}peek() { // 查看栈顶元素    if (this.isEmpty()) {        return "Stack is empty";    }    return this.items[this.items.length - 1];}isEmpty() {    return this.items.length === 0;}size() {    return this.items.length;}}

const stack = new MyStack();stack.push(10);

以上就是JS数组如何创建和操作的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1516699.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 10:15:13
下一篇 2025年12月20日 10:15:31

相关推荐

  • React 应用中图片加载优化指南

    本文旨在帮助开发者优化 React 应用中的图片加载速度,解决因图片过大导致的加载缓慢问题。通过分析 Unsplash API 的使用场景,介绍了如何选择合适的图片分辨率,并结合其他优化策略,提升用户体验。本文将提供代码示例和实用技巧,帮助开发者高效地处理图片资源。 在构建 React 应用时,图片…

    2025年12月20日 好文分享
    000
  • React 应用中图片加载优化:提升性能的实用指南

    本文旨在解决 React 应用中使用 Unsplash API 加载图片时遇到的性能问题。通过分析问题根源,即加载过大尺寸的图片,本文提供了优化方案,包括选择合适的图片尺寸、使用图片懒加载、优化图片格式等,帮助开发者显著提升图片加载速度,改善用户体验。 在 react 应用中,高效的图片加载对于提供…

    2025年12月20日 好文分享
    000
  • React 应用中图片加载优化:提升性能的实用技巧

    本文针对React应用中图片加载缓慢的问题,提供了一系列优化方案。通过分析Unsplash API的使用场景,重点讲解了如何选择合适的图片尺寸、实现图片懒加载、以及利用缓存策略等方法,有效提升页面加载速度和用户体验。掌握这些技巧,能显著改善React应用的性能,尤其是在处理大量图片时。 在react…

    2025年12月20日 好文分享
    000
  • React 应用中图片加载优化:从慢速到高效的实践指南

    本文深入探讨了在React应用中处理外部API(如Unsplash)图片加载缓慢的问题。核心解决方案在于选择合适的图片分辨率,避免加载过大的原始图片,从而显著提升页面性能和用户体验。文章将通过代码示例,详细阐述如何优化图片URL选择,并延伸介绍其他重要的图片加载优化策略。 理解图片加载性能瓶颈 在现…

    2025年12月20日 好文分享
    000
  • 动态参数签名的函数调用:使用策略模式实现灵活的业务逻辑

    本文探讨了在JavaScript/TypeScript中,如何优雅地处理根据不同业务场景(如面试类型)调用参数签名不同的函数。通过引入策略设计模式,我们将展示如何定义统一的接口,封装各自的业务逻辑,从而实现代码的解耦、提高可维护性和扩展性,有效解决动态参数传递的挑战。 业务场景与问题描述 在复杂的业…

    2025年12月20日
    000
  • 灵活调用不同参数签名的函数:策略模式实践指南

    本文探讨了如何在JavaScript应用中,当函数调用需要根据不同上下文处理不同参数签名时,优雅地设计和实现解决方案。通过引入策略设计模式,我们将展示如何封装特定于上下文的逻辑,从而实现统一的函数调用接口,提升代码的可扩展性、可维护性和清晰度,尤其适用于处理面试官验证这类场景。 挑战:不同场景下的函…

    2025年12月20日
    000
  • 利用策略模式优化不同参数函数调用的设计

    针对JavaScript中根据不同业务场景调用参数数量可变的函数,本文介绍如何运用策略模式进行优雅设计。通过定义统一接口和具体策略类,实现动态选择并执行具有不同参数签名的函数,从而提高代码的灵活性、可维护性与扩展性,有效解决传统硬编码或条件判断导致的复杂性。 在软件开发中,我们经常会遇到需要根据特定…

    2025年12月20日
    000
  • 精准控制Vite + Svelte动态导入:实现条件式代码消除与优化

    本教程深入探讨在Vite和Svelte项目中如何实现条件式动态导入的代码消除。文章解释了动态导入默认的代码分割行为,并强调若要实现真正的死代码消除,必须依赖静态可分析的条件。通过详细讲解Vite的环境变量机制,教程提供了实用的代码示例,指导开发者确保只有实际执行的模块才被包含在最终构建产物中,从而有…

    2025年12月20日
    000
  • 优化Vite + Svelte中的条件动态导入:实现按需打包

    优化Vite + Svelte中的条件动态导入:实现按需打包 本文探讨vite和svelte项目中条件动态导入的打包行为,指出默认情况下,即使代码分支永不执行,相关模块也可能被包含在最终构建中。我们将深入解析打包器的工作原理,并提供两种有效策略:利用静态可分析条件和vite环境变量,以实现真正的按需…

    2025年12月20日
    000
  • Vite与Svelte中条件动态导入的优化策略与按需打包

    本文探讨了在Vite和Svelte项目中,如何优化条件动态导入以实现更精确的按需打包。尽管动态导入本身支持代码分割,但若希望未执行的代码分支在生产构建中被彻底移除(树摇),则需要确保条件语句可被静态分析。文章详细介绍了通过使用Vite环境变量等方式,实现 bundler 对条件分支的识别和优化,从而…

    2025年12月20日
    000
  • 掌握Vite中条件动态导入的死代码消除:基于静态分析的优化实践

    本文探讨了在Vite和Svelte项目中,如何优化条件动态导入以实现死代码消除。面对复杂条件导致未使用的模块仍被打包的问题,文章阐述了静态分析的重要性。通过利用Vite内置的环境变量机制,我们能够构建可被打包工具识别的条件,从而有效剔除生产环境中未被实际执行的动态导入模块,减小最终包体积。 理解条件…

    2025年12月20日
    000
  • 生成指定日期范围内按月分组的日期数组

    本文将介绍如何使用原生 JavaScript 生成一个包含指定日期范围内所有日期的数组,并按月份进行分组。无需任何第三方库,即可实现类似 [May – month name, [1st May, 2nd May, 3rd May, …], June, [1st June, 2…

    2025年12月20日
    000
  • JavaScript模态框交互:解决弹出层关闭按钮无效问题

    本教程旨在解决JavaScript中创建图片弹出模态框时,关闭按钮点击无效的问题。核心原因在于打开和关闭事件触发器重叠或事件冒泡。解决方案是明确分离模态框的打开与关闭事件监听器,并推荐使用CSS类来管理模态框的显示状态,从而避免事件冲突,提升交互的稳定性和代码的可维护性。 在构建交互式前端界面时,常…

    2025年12月20日 好文分享
    000
  • 前端开发:基于表单输入值动态控制HTML元素显示

    本教程详细介绍了如何在前端开发中,根据用户在表单输入框中填写的值,动态控制另一个HTML元素的显示或隐藏。通过sessionStorage实现跨页面数据传递,并利用JavaScript结合CSS的两种方法(直接修改display属性或切换CSS类)来实现元素的条件渲染,确保页面内容的灵活性和用户体验…

    好文分享 2025年12月20日
    000
  • 解决React中Debounced搜索在移动端过滤失效:大小写敏感性陷阱

    本教程探讨React应用中,使用防抖(Debounce)功能的搜索框在桌面端正常,但在移动端过滤失效的问题。核心原因在于移动设备输入自动首字母大写与过滤逻辑中数据源的小写转换处理不一致。文章将提供详细分析及解决方案,通过统一大小写处理来确保搜索功能在所有设备上稳定运行。 在react应用开发中,为提…

    2025年12月20日
    000
  • JavaScript中DOM元素访问的常见陷阱与解决方案

    本文旨在解决JavaScript中通过document.getElementById()获取DOM元素时返回null的问题。核心在于理解脚本执行时机与DOM解析状态。通过正确放置标签或利用DOMContentLoaded事件,可以确保在元素可用时再尝试访问,从而有效避免此类错误。 理解DOM元素访问…

    2025年12月20日
    000
  • React移动端防抖搜索过滤异常:大小写敏感性陷阱

    本文深入探讨了React应用中防抖搜索功能在移动设备上过滤异常的问题。核心原因在于移动设备键盘的自动首字母大写功能与搜索逻辑中大小写处理不一致,导致搜索值与数据项无法正确匹配。文章提供了详细的解决方案,即在进行比较前,确保搜索值和数据项属性都转换为小写,并强调了跨设备测试和一致性大小写处理的重要性。…

    2025年12月20日
    000
  • 如何在Three.js中创建透明背景的Canvas

    本文详细介绍了在Three.js中实现Canvas透明背景的完整教程。核心步骤包括在初始化渲染器时通过alpha: true参数启用Alpha通道,然后使用renderer.setClearColor(0x000000, 0)将渲染器背景色设置为完全透明。通过这些设置,Three.js Canvas…

    2025年12月20日
    000
  • 解决React防抖搜索在移动设备上过滤异常:大小写敏感性陷阱与解决方案

    本文深入探讨了React应用中,使用防抖(Debounce)搜索功能在移动设备上出现过滤异常的问题。核心原因在于搜索值与数据项在比较时的大小写不一致,尤其是在移动设备自动首字母大写的情况下。教程将详细分析问题根源,并提供确保搜索逻辑大小写一致性的解决方案,以实现跨平台稳定过滤。 React 防抖搜索…

    2025年12月20日
    000
  • 解决HTML Canvas溢出屏幕的教程

    当HTML canvas元素在浏览器中出现溢出或滚动条时,通常是由于其默认的inline显示属性或缺少HTML5文档类型声明所致。本教程将深入探讨这些常见问题,并提供两种核心解决方案:通过CSS将canvas设置为display: block,或确保HTML文档声明为a style=”c…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信