forEach没有返回值vara=[1,2,3,4,5]varb=a.forEach((item)=>{item=item*2})console.log(b)//undefined不能打断forEach的执行遍历过程中不能打断执行。如果要在满足某个条件时中断遍历,就必须使用for循环。vararr=[1,2,3];对于(vari=0;i{console.log('item',item)//nullundefined});上面代码中,forEach()方法不会跳过undefined和null,而是会跳过空格。for循环不会跳过空格,它会被认为是未定义的。改变数组的情况我们来看几个例子:vara=[1,2,3,4,5]a.forEach((item)=>{item=item*2})console.log(a)//[1,2,3,4,5]这里原来的数组没有变化。vara=[1,'1',{num:1},true]a.forEach((item,index,arr)=>{item=2})console.log(a)//[1,'1',{num:1},true]这里修改了item的值,但仍然没有修改原数组。vara=[1,'1',{num:1},true]a.forEach((item,index,arr)=>{item.num=2item=2})console.log(a)//[1,'1',{num:2},true]修改数组中对象的某个属性时,发现属性发生了变化。其他值保持不变。为什么会这样?这里我们将介绍栈内存和堆内存的概念。前端对JS中基本数据类型的训练,如String、Number、Boolean、Undefined、Null等,都存在于栈内存中。将变量名及其对应的值存储在.Object、Array、Function存在于堆内存中,并在堆内存中存储变量名和引用位置。在第一个例子中,为什么不能通过直接修改item来修改原数组,因为item的值不是对应原数组中的值,而是重新创建一个与原数组具有相同值的新变量。因此,如果项目是基本数据类型,数组中的值将不会改变。如果是引用类型,那么数组中的item和value指向同一个内存地址就会发生变化。在第二个例子中,数组中对象的值并没有改变,因为虽然新创建的变量和原数组中的对象指向同一个地址,但是改变的是新变量的值,也就是重新赋值,即新对象的值为2,而原数组中的对象仍为{num:1}。第三个例子中,由于对象是引用类型,新对象和旧对象都指向同一个地址,所以新对象将num变为2,原数组中的对象也发生变化。vara=[1,2,3,4,5]a.forEach((item,index,arr)=>{arr[index]=item*2})console.log(a)//[2,4,6,8,10]在回调函数中改变arr的值,原来的数组变了。这个例子其实和例子3是一样的,参数中的arr只是原数组的一个副本,但是arr是一个引用类型。如果修改数组中的某一项,原数组也会改变,因为它指向同一个引用地址,而如果给参数arr赋其他值,即重新赋值,原数组不会改变.如下:vara=[1,2,3,4,5]a.forEach((item,index,arr)=>{arr=2})console.log(a)//[1,2,3,4,5]map有返回值返回一个处理后的新数组,但不改变原数组的值。变量a=[1,2,3,4,5]变量b=a。map((item)=>{returnitem=item*2})控制台。log(a)//[1,2,3,4,5]console.log(b)//[2,4,6,8,10]无法中断执行同forEach,无法中断执行跳过空位和forEach一样,会跳过空位改变数组原图可以改变数组的情况和原理和forEach一样性能对比1.当然,for循环是最简单的,因为它没有任何附加功能调用堆栈和上下文;2.ForEach其次,因为它其实比我们想象的要复杂,它的函数签名其实是array.forEach(function(currentValue,index,arr),thisValue),这并不是普通for循环的语法糖,以及执行时需要考虑的参数和上下文较多,可能会降低性能3、map最慢,因为它的返回值是一个全新的等长数组,数组创建和赋值的性能开销很高。