JS中多方式数组复制知识扩展

JS中多方式数组复制知识扩展

  • 前言
  • 浅拷贝
    • JavaScript 展开操作符
    • for() 循环
      • 其他:
    • array.forEach
      • forEach方法详解
    • array.map
      • map()方法详解
    • array.filter
      • filter()方法详解
    • array.reduce
      • reduce()方法详解
    • array.slice
      • slice()方法详解
    • Array.from
      • Array.from()方法详解
  • 深拷贝

前言

在这篇文章中,我们将探讨多种复制JavaScript数组的方法,并详细解释这些方法的具体应用。这不仅是对我自身知识的一个总结和备忘,同时也希望能够为读者提供一些有用的参考与启发。希望本文能在您解决数组复制问题时提供帮助,并拓展您对JavaScript的理解。

首先明确一个点:数组/对象值是按 引用 而不是按 复制的。

接下来我们将分浅拷贝和深拷贝来写几个js数组的复制

关于深拷贝和浅拷贝可以看我的另一篇文章:JS中对象的浅拷贝,深拷贝和引用-CSDN博客

浅拷贝

JavaScript 展开操作符

自从 ES6 发布以来,这一直是最受欢迎的方法。这是一个简短的语法。

numbers = [1, 2, 3];
numbersCopy = [...numbers];

**注意:**这不能安全地复制多维数组。数组/对象值是按 引用 而不是按 复制的。

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]

由于是浅拷贝,像下面这样想复制多维数组就不符合要求了:

nestedNumbers = [[1], [2]];
numbersCopy = [...nestedNumbers];numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// They've both been changed because they share references

for() 循环

考虑到函数式编程在业界的流行程度,我认为这种方法 最不受欢迎

numbers = [1, 2, 3];
numbersCopy = [];for (i = 0; i < numbers.length; i++) {numbersCopy[i] = numbers[i];
}

注意: 这不能安全地复制多维数组。由于你使用的是 = 运算符,因此它将按 引用 而不是按 分配对象/数组。

其他:

for循环时同步的,这意味着在代码的执行过程中,for循环会逐步执行每一次迭代,直到循环结束,然后再继续执行循环后的代码。然而,如果你在for循环中使用了异步操作(例如setTimeoutPromise),那么这些异步操作的执行顺序将取决于事件循环机制,比如当循环中包含异步函数时(例如setTimeoutPromise),这些异步操作会被推送到事件队列中,而主线程会继续执行后续代码。

具体来说,setTimeout会将其回调函数推送到事件队列中,并在指定时间到达后将其放入执行队列。这意味着主线程不会在setTimeout执行时阻塞,而是会继续执行后续代码。

写一个示例:

for (let i = 0; i < 3; i++) {setTimeout(() => {console.log(i);}, 1000);
}
console.log('Done1');
for (let i = 0; i < 3; i++) {setTimeout(() => {console.log(100 - i);}, 500);
}
console.log('Done2');
for (let i = 0; i < 3; i++) {setTimeout(() => {console.log(50 - i);}, 500);
}
console.log('Done3');

执行步骤如下:

  1. 执行第一个 for 循环:依次将 3 个 setTimeout 回调函数推送到事件队列中,这些回调函数将在 1000 毫秒(1秒)后执行。
    • 回调函数1:console.log(i) 在 1 秒后输出 0
    • 回调函数2:console.log(i) 在 1 秒后输出 1
    • 回调函数3:console.log(i) 在 1 秒后输出 2
  2. 打印 Done:立即执行。
  3. 执行第二个 for 循环:依次将 3 个 setTimeout 回调函数推送到事件队列中,这些回调函数将在 500 毫秒(0.5秒)后执行。
    • 回调函数1:console.log(100 - i) 在 0.5 秒后输出 100
    • 回调函数2:console.log(100 - i) 在 0.5 秒后输出 99
    • 回调函数3:console.log(100 - i) 在 0.5 秒后输出 98
  4. 打印 Done2:立即执行。
  5. 执行第三个 for 循环:依次将 3 个 setTimeout 回调函数推送到事件队列中,这些回调函数将在 500 毫秒(0.5秒)后执行。
    • 回调函数1:console.log(50 - i) 在 0.5 秒后输出 50
    • 回调函数2:console.log(50 - i) 在 0.5 秒后输出 49
    • 回调函数3:console.log(50 - i) 在 0.5 秒后输出 48
  6. 打印第二个 Done2:立即执行。
  7. 定时器到达,按照设定的时间顺序执行 setTimeout 回调函数。

所以,实际的打印顺序如下:

Done1
Done2
Done3
100
99
98
50
49
48
0
1
2
  • DoneDone2 会在任何 setTimeout 回调函数之前立即打印,因为它们是同步的。
  • 第二个 for 循环的 setTimeout 回调函数将在 0.5 秒后执行,因此它们的输出先于第一个 for 循环的输出。
  • 第三个 for 循环的 setTimeout 回调函数也将在 0.5 秒后执行,因此它们与第二个 for 循环几乎同时输出。
  • 第一个 for 循环的 setTimeout 回调函数将在 1 秒后执行,因此它们的输出最后。

array.forEach

forEach 是 JavaScript 数组的一个原型方法,用于对数组中的每个元素依次执行给定的函数。与传统的 for 循环不同,forEach 通过回调函数的形式来处理数组元素,简化了数组遍历的代码书写,并提高了代码的可读性和可维护性。

numbers = [1, 2, 3];
numbersCopy = []
numbers.forEach(item => {numbersCopy.push(item)
})

forEach方法详解

  1. 参数详解:

    array.forEach(callback(currentvalue,index,arr) ,thisValue)callback为数组中每个元素执行的函数,该函数可接受1-3个参数:currentvalue参数表示数组的当前元素项,必须的参数index参数表示的当前元素下标,可选参数arr参数表示当前元素所属的数组,可选参数thisValue表示执行回调函数callback()时的this指向。可选参数。当不写时,则默认是指向window全局2
    
  2. 示例:

    注意点:

    • forEach()是没有返回值的

    • forEach()会跳过空值

    • forEach() 方法无法提前结束: forEach 方法无法通过 breakreturn 提前终止循环。如果需要中途退出循环,应该考虑使用 for 循环或 someevery 等方法。

    var arr = [1, 3, 5, 13, 2];
    var res = arr.forEach(function(item,index) {console.log(`数组第${index+1}个元素是${item}`);
    })
    console.log(res);//forEach的返回值为undefined,
    

    用forEach()方法修改数组元素不能使用item直接修改,item相当于从arr2中复制过来的值,并不是真正指向原数组arr里面的元素。所以我们想要修改原数组的每个元素必须通过拿到它的索引值index去进行修改:arr[index] = 2;(当然是浅拷贝,对象中的数据还是可以改变的)

  3. 是同步的,处理机制和上面的for循环相同,就不重复叙述了

array.map

map 函数是映射。映射起源于数学,map 是在保留结构的同时将集合转换为另一种类型的集合的概念,这意味着 Array.map 每次都会返回相同长度的数组。

numbers = [1, 2, 3];
numbersCopy = numbers.map((x) => x);

如果你想更加数学化,(x) => x 被称为恒等,它返回给定的任何参数。

map(identity) 拷贝一个列表。

identity = (x) => x;
numbers.map(identity);
// [1, 2, 3]

注意: 这也是通过 引用 而不是 来分配对象/数组,下面几种也是这个意思,就不一一举例说明了。

当然,map是对数据的每一项进行操作,你可以进行复制,当然也可以进行其他的操作,比如每个数据乘以2等等等等,用它做复制可能有一点点功能浪费,但是确实能做,简要扩展:

map()方法详解

  1. map() 的返回值是一个新的数组,新数组中的元素为 “原数组调用函数处理过后的值”

  2. map()函数的参数详解

    一般参数是一个回调函数
    array.map((item,index,arr)=>{//item是操作的当前元素//index是操作元素的下标//arr是需要被操作的元素//具体需要哪些参数 就传入那个
    })
    
  3. 示例

    const array = [2, 3, 4, 4, 5, 6]
    const map2=array.map((item,index,arr)=>{console.log("操作的当前元素",item)console.log("当前元素下标",index)console.log("被操作的元素",arr)//对元素乘以2return item*2
    })
    console.log("处理之后先产生的数组map",map2)以第一次返回结果为例,打印结果为:
    操作的当前元素,2
    当前元素下标,0
    被操作的元素,[2, 3, 4, 4, 5, 6]
    第二次为:
    操作的当前元素,3
    当前元素下标,1
    被操作的元素,[2, 3, 4, 4, 5, 6]
    最后的map数据为:
    处理之后先产生的数组map,[4, 6, 8, 8, 10, 12]
    
  4. 总结:map()方法经常拿来遍历数组,但是不改变原数组,但是会返回一个新的数组

  5. 注意:有时候会出现这种现象,出现几个undefined

     const array = [2, 3, 4, 4, 5, 6]console.log("原数组array为",array)const map = array.map(x => {if (x == 4) {return x * 2}})结果为:
    [undefined, undefined, 8, 8, undefined, undefined]
    
  6. 是同步方法,处理机制和上面的for循环相同,就不重复叙述了

array.filter

此函数会返回一个数组,就像 map 一样,但是不能保证长度相同,因为它是为了过滤,filter 函数对数组中的每个元素都会执行一次回调函数,如果回调函数返回 true,则将该元素添加到新数组中;如果返回 false,则不添加。这使得 filter 成为一种方便的方法来创建满足特定条件的新数组

这里我们将让filter 始终返回 true,则将获得重复项:

numbers = [1, 2, 3];
numbersCopy = numbers.filter(() => true);

filter()方法详解

  1. 参数详解

    Array.filter(function(element, indedx, array), thisArg)element: 当前被处理的元素。
    index(可选): 当前被处理的元素的索引。
    array(可选): 调用 filter 的数组。
    thisArg(可选): 执行函数时,用于设置 this 的值。
    
  2. 官方写法

    const people = [{ name: "Alice", age: 25 },{ name: "Bob", age: 30 },{ name: "Charlie", age: 20 },
    ];const adults = people.filter(function (person) {return person.age >= 25;
    });console.log(adults); // 输出: [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }]
    
  3. 使用箭头函数(更常用):

    const numbers = [10, 20, 30, 40, 50];
    const greaterThan30 = numbers.filter((num) => num > 30);console.log(greaterThan30); // 输出: [40, 50]
    
  4. 自定义过滤函数:

    // 自定义过滤函数,筛选出年龄大于等于 25 的人
    function filterAdult(person) {return person.age >= 25;
    }const people = [{ name: "Alice", age: 25 },{ name: "Bob", age: 30 },{ name: "Charlie", age: 20 },
    ];// 使用自定义过滤函数
    const adults = people.filter(filterAdult);console.log(adults);
    // 输出: [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }]
    
  5. 是同步方法,处理机制和上面的for循环相同,就不重复叙述了

array.reduce

reduce() 是数组的归并方法,与forEach()、map()、filter()等迭代方法一样都会对数组每一项进行遍历,但是reduce() 可同时将前面数组项遍历产生的结果与当前遍历项进行运算,这一点是其他迭代方法无法企及的。

我觉得使用 reduce 拷贝数组很糟糕,因为它的功能远不止于此。但是也能做:

numbers = [1, 2, 3];numbersCopy = numbers.reduce((newArray, element) => {newArray.push(element);return newArray;
}, []);

reduce 循环遍历列表时,转换初始值。

这里的初始值是一个空数组,我们将使用每个元素填充它。该数组必须从函数中返回,以在下一次迭代中使用。

reduce()方法详解

  1. 参数详解:

    arr.reduce(function(prev,cur,index,arr){
    ...
    }, init);回调函数参数:
    prev 表示上一次调用回调返回的值,或者是提供的初始值(init) 必须;
    cur 表示当前正在处理的数组元素 必须;
    index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1 可选;
    arr 表示原数组 可选;init 表示初始值 可选。常用的参数只有两个:prev 和 cur
    
  2. 示例说明:

    先提供一个原始数组:
    var arr = [3,9,4,3,6,0,9];1. 求数组项之和
    var sum = arr.reduce(function (prev, cur) {return prev + cur;
    },0);由于传入了初始值0,所以开始时prev的值为0,cur的值为数组第一项3,相加之后返回值为3作为下一轮回调的prev值,然后再继续与下一个数组项相加,以此类推,直至完成所有数组项的和并返回。2. 求数组项最大值
    var max = arr.reduce(function (prev, cur) {return Math.max(prev,cur);
    });// 数组最大值 
    const max = arr.reduce(function(pre, cur) {return pre>cur?pre:cur;
    }); 由于未传入初始值,所以开始时prev的值为数组第一项3,cur的值为数组第二项9,取两值最大值后继续进入下一轮回调。
    
  3. 箭头函数:

     // 数组求和
    const arr = [12, 34, 23];
    const sum = arr.reduce((total, num) => total + num);
    <!-- 设定初始值求和 -->
    const arr = [12, 34, 23];
    const sum = arr.reduce((total, num) => total + num, 10);  // 以10为初始值求和
    <!-- 对象数组求和 -->
    var result = [{ subject: 'math', score: 88 },{ subject: 'chinese', score: 95 },{ subject: 'english', score: 80 }
    ];
    const sum = result.reduce((accumulator, cur) => accumulator + cur.score, 0); 
    const sum = result.reduce((accumulator, cur) => accumulator + cur.score, -10);  // 总分扣除10分
    // 记录元素出现次数
    let arr5 = ['name','age','long','short','long','name','name'] 
    let arrResult1 = arr.reduce((pre,cur) =>{console.log(pre,cur)if(cur in pre){pre[cur]++}else{pre[cur] = 1}return pre
    },{})console.log(arrResult1)//结果:{name: 3, age: 1, long: 2, short: 1}
    
  4. 简要总结

    使用arr.reduce(function(prev,cur,index,arr){
    ...
    }, init);
    如果没有init,初始状态这个prev就是arr的第一个值,cur就是arr的第二个值,一次计算之后,prev变成了计算的结果,cur遍历到第三个值,一直结束,这种结果可想而知,结果的数据类型就是arr里面值的类型,比如是数字数组,那结果大概率数字,字符串数组,结果大概率是字符串(当然你也可以计算字符串长度和,当然也行),总之最后的结果是一个值;
    那如果你想得到一个数组呢?你可以将init设置为[],这样初始状态prev就是[],cur就是arr的第一个值,你可以对这个值处理如何添加到prev中去,再return prev就是一个数组,如上面的示例,复制数组;当然你也可以将初始值设置为字典{},如上面记录元素出现次数。
    
  5. 是同步方法,处理机制和上面的for循环相同,就不重复叙述了

array.slice

**slice()**方法提取数组的一部分元素,并返回一个新的数组。

**slice()**方法提取的元素开始在给定的start参数,并在给定的端部end参数(end不包括)。原始数组不被会更改。

如果我们想得到所有元素,不提供任何参数:

numbers = [1, 2, 3, 4, 5];
numbersCopy = numbers.slice();
// [1, 2, 3, 4, 5]

slice()方法详解

  1. 参数详解

    array.slice(start, end)start (可选)从零开始的索引,从该索引开始提取,使用负数从数组的末尾进行选择。如果省略,则类似于0。
    end (可选)从零开始的索引,终止提取之前,如果省略,将选择从开始位置到数组末尾的所有元素。使用负数从数组末尾进行选择。注释:slice() 方法不会改变原始数组。
    
  2. 示例

    如果我们想得到前 3 个元素:
    [1, 2, 3, 4, 5].slice(0, 3);
    // [1, 2, 3]
    如果我们想得到后 3 个元素:
    [1, 2, 3, 4, 5].slice(3);
    // [3, 4, 5]
    使用负数(从后面选取数据):
    [1, 2, 3, 4, 5].slice(-3-1);
    // [3, 4]
    
  3. 是同步方法,处理机制和上面的for循环相同,就不重复叙述了

Array.from

Array.from()方法就是将一个类数组对象或者可迭代的对象转换成一个真正的数组,也是ES6的新增方法。

这可以将任何可迭代对象转换为数组。输入数组将返回浅拷贝。

numbers = [1, 2, 3];
numbersCopy = Array.from(numbers);
// [1, 2, 3]

Array.from()方法详解

  1. 参数详解

    Array.from(object, mapFunction, thisValue)object	必需,要转换为数组的对象。
    mapFunction	可选,数组中每个元素要调用的函数。
    thisValue	可选,映射函数(mapFunction)中的 this 对象。
    
  2. 将类数组对象转换为真正数组

    什么是类数组对象呢?所谓类数组对象,最基本的要求就是具有length属性的对象

    let arrayLike = {0: 'tom', 1: '65',2: '男',3: ['jane','john','Mary'],'length': 4
    }
    let arr = Array.from(arrayLike)
    console.log(arr) // ['tom','65','男',['jane','john','Mary']]
    

    将上面代码中length属性去掉呢?实践证明,答案会是一个长度为0的空数组。

    这里将代码再改一下,就是具有length属性,但是对象的属性名不再是数字类型的,而是其他字符串型的,代码如下:

    let arrayLike = {'name': 'tom', 'age': '65','sex': '男','friends': ['jane','john','Mary'],length: 4
    }
    let arr = Array.from(arrayLike)
    console.log(arr)  // [ undefined, undefined, undefined, undefined ]

    会发现结果是长度为4,元素均为undefined的数组

    由此可见,要将一个类数组对象转换为一个真正的数组,必须具备以下条件

    1、该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。

    2、该类数组对象的属性名必须为数值型或字符串型的数字

    ps: 该类数组对象的属性名可以加引号,也可以不加引号

  3. 将Set结构的数据转换为真正的数组(常用于数组去重):

    let arr = Array.from(new Set([1, 2, 1, 2]))
    console.log(arr) //[1, 2]
    

    Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。如下:

    let arr = [12,45,97,9797,564,134,45642]
    let set = new Set(arr)
    console.log(Array.from(set, item => item + 1)) // [ 13, 46, 98, 9798, 565, 135, 45643 ]
    
  4. 将字符串转换为数组:

    let  str = 'hello world!';
    console.log(Array.from(str)) // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "!"]
    
  5. Array.from参数是一个真正的数组:

    console.log(Array.from([12,45,47,56,213,4654,154]))
    
  6. 是同步方法,处理机制和上面的for循环相同,就不重复叙述了

深拷贝

这里就先提供一种方式:

JSON.parse(JSON.stringify(array));

JSON.stringify 将一个对象转换成一个字符串。

JSON.parse 将一个字符串转换成一个对象。

将它们组合在一起可以将一个对象变成一个字符串,然后反过来可以创建一个全新的数据结构。

注意:这个方法可以安全地复制深度嵌套的对象/数组!

nestedNumbers = [[1], [2]];
numbersCopy = JSON.parse(JSON.stringify(nestedNumbers));numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);// [[1], [2]]
// [[1, 300], [2]]
// These two arrays are completely separate!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/63223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hive 中 Order By、Sort By、Cluster By 和 Distribute By 的详细解析

Hive 中 Order By、Sort By、Cluster By 和 Distribute By 的详细解析 在 Hive 数据查询与处理操作中&#xff0c;Order By、Sort By、Cluster By 和 Distribute By 这些语句对于数据的排序、分区以及在 Reduce 阶段的处理起着关键作用。本文将详细解析它们各自的语法、区别以…

okHttp的tcp连接池的复用

okhttp的连接池是tcp连接池吧&#xff0c;是两台机器之间的连接&#xff0c;ip:port连接&#xff0c;然后具体的接口再添加具体的url吗&#xff1f; 具体的 HTTP 请求&#xff08;包括 URL、请求方法、头部等&#xff09;则是在复用的 TCP 连接上进行传输的。 是的&#xff0c…

Linux 正确关机方式详解

在Linux系统中&#xff0c;正确地关机是一个重要的操作&#xff0c;它不仅影响到系统的数据完整性&#xff0c;还可能影响到其他用户的工作。本文将详细介绍Linux系统中的各种关机方式&#xff0c;包括它们的使用场景和具体命令。 为什么需要正确关机 在DOS和Windows系统中&a…

在商业智能BI系统中,如何配置高级感的数据可视化折线图?

在数据可视化的世界里&#xff0c;折线图作为一种直观且有效的数据展示方式&#xff0c;被广泛应用于各类数据分析与报告中。折线图不仅能够清晰地展示数据随时间或其他连续变量的变化趋势&#xff0c;还能通过不同的样式配置&#xff0c;增强图表的可读性和美观度。在JVS-智能…

容器镜像仓库

文章目录 1、docker hub1_注册2_登录3_创建容器镜像仓库4_在本地登录Docker Hub5_上传容器镜像6_下载容器镜像 2、harbor1_获取 docker compose二进制文件2_获取harbor安装文件3_获取TLS文件4_修改配置文件5_执行预备脚本6_执行安装脚本7_验证运行情况8_访问harborUI界面9_harb…

网站打开速度测试工具:互联网优化的得力助手

在信息飞速流转的互联网时代&#xff0c;网站如同企业与用户对话的窗口&#xff0c;其打开速度直接关乎用户体验&#xff0c;乃至业务的成败。所幸&#xff0c;一系列专业的网站打开速度测试工具应运而生&#xff0c;它们宛如幕后的技术侦探&#xff0c;精准剖析网站性能&#…

liunx docker 部署 nacos seata sentinel

部署nacos 1.按要求创建好数据库 2.创建docker 容器 docker run -d --name nacos-server -p 8848:8848 -e MODEstandalone -e SPRING_DATASOURCE_PLATFORMmysql -e MYSQL_SERVICE_HOST172.17.251.166 -e MYSQL_SERVICE_DB_NAMEry-config -e MYSQL_SERVICE_PORT3306 -e MYSQL…

PHP 与 MySQL 搭配的优势

一、PHP 与 MySQL 搭配的优势 强大的动态网页开发能力 PHP 是一种服务器端脚本语言&#xff0c;能够生成动态网页内容。它可以根据用户的请求、数据库中的数据等因素&#xff0c;实时地生成 HTML 页面返回给客户端浏览器。而 MySQL 是一个流行的关系型数据库管理系统&#xf…

爬虫项目基础知识详解

文章目录 Python爬虫项目基础知识一、爬虫与数据分析1.1 Python中的requests库Requests 库的安装Requests 库的 get() 方法爬取网页的通用代码框架HTTP 协议及 Requests 库方法Requests 库主要方法解析 1.2 python中的json库1.3 xpath学习之python中lxml库html了解html结构html…

结构型-组合模式(Composite Pattern)

什么是组合模式 又名部分整体模式&#xff0c;是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象&#xff0c;用来表示部分以及整体层次。这种类型的设计模式属于结构型模式&#xff0c;它创建了对象组的树形结构。 结构 抽象根节点&#xff08;Co…

防止浏览器控制台修改网页数据与函数的方法

最近&#xff0c;解决了一个网络视频学习的两个问题&#xff1a;过10分钟就暂停并显示提示窗口、不能自动跳到下个章节&#xff0c;思路是&#xff1a;在控制台上运行一段编写的脚本代码&#xff0c;重定义该网页上一个函数&#xff08;解决人工确认问题&#xff09;&#xff1…

Wordpress设置固定链接形式后出现404错误

比如固定连接设置为 /archives/%post_id%.html 这种形式&#xff0c;看起来比较舒服。对搜索引擎也友好。 出现404需要设置伪静态

小程序项目的基本组成结构

分类介绍 项目根目录下的文件及文件夹 pages文件夹 用来存放所有小程序的页面&#xff0c;其中每个页面都由4个基本文件组成&#xff0c;它们分别是&#xff1a; .js文件&#xff1a;页面的脚本文件&#xff0c;用于存放页面的数据、事件处理函数等 .json文件&#xff1a;…

什么是Bug,bug怎么提交

1 bug的定义与起源 Bug在计算机科学中通常指的是程序或系统中的错误或缺陷&#xff0c;导致其无法按预期执行。这种错误可能源于代码中的逻辑错误、输入输出的意外处理、资源分配不当等问题。Bug的产生与多方面因素有关&#xff0c;包括程序员未能正确实现软件的特定规格或设定…

Agent AI: Surveying the Horizons of Multimodal Interaction---摘要、引言、代理 AI 集成

题目 智能体AI:多模态交互视野的考察 论文地址&#xff1a;https://arxiv.org/abs/2401.03568 图1&#xff1a;可以在不同领域和应用程序中感知和行动的Agent AI系统概述。Agent AI是正在成为通用人工智能&#xff08;AGI&#xff09;的一个有前途的途径。Agent AI培训已经证…

前端开发入门指南Day 17:TypeScript高级类型(泛型,类型守卫,Partial<T>和 Required<T>等)

泛型&#xff1a;代码的"变色龙" &#x1f98e; 为什么需要泛型&#xff1f; 想象一个快递员&#xff0c;每天要处理不同类型的包裹。如果为每种类型的包裹都写一套处理程序&#xff0c;那会很麻烦。泛型就像是一个"通用的包裹处理系统"&#xff0c;它能…

LRU Cache替换算法

目录 1.什么是LRU Cache&#xff1f; 2.LRU Cache 的底层结构 3.LRU Cache的实现 LRUCache类中的接口总览 构造函数 get操作 put操作 打印 4.LRU Cache的测试 5.LRU Cache相关OJ题 6.LRU Cache类代码附录 1.什么是LRU Cache&#xff1f; 首先我想解释一下什么是cach…

小米二面:JVM 触发类加载的条件有哪些?

类加载生命周期 类加载的生命周期包括&#xff1a;加载&#xff08;Loading&#xff09;、链接&#xff08;Linking&#xff09; 和 初始化&#xff08;Initialization&#xff09;。而其中&#xff0c;初始化阶段是决定类是否被真正加载的关键。 JVM 在什么时候启动类加载过…

数字孪生与大型模型强强联合,共塑工业制造崭新前景

随着新一代信息技术与实体经济的加速融合&#xff0c;工业领域的数字化、智能化转型趋势愈发显著&#xff0c;孕育出一系列制造业数字化转型的新模式与新业态。在此背景下&#xff0c;数字孪生技术作为关键支撑力量&#xff0c;正在全球范围内迅速崛起并得到广泛应用&#xff0…

【笔记2-5】ESP32:freertos消息队列

主要参考b站宸芯IOT老师的视频&#xff0c;记录自己的笔记&#xff0c;老师讲的主要是linux环境&#xff0c;但配置过程实在太多问题&#xff0c;就直接用windows环境了&#xff0c;老师也有讲一些windows的操作&#xff0c;只要代码会写&#xff0c;操作都还好&#xff0c;开发…