JavaScript 高阶函数-map

目录

一、map 是什么?

二、基本语法

参数说明(前 3 个是处理函数的参数,最常用前 2 个)

三、核心特性(重点)

四、实际示例(从简单到复杂)

示例 1:基础用法 —— 数组元素翻倍

示例 3:处理对象数组(开发最常用)

示例 4:省略 return 的坑

五、map 与 forEach 的区别(易混淆,必看)

六、注意事项

总结


map是 JavaScript 数组的高阶函数,以下从定义、用法、核心特性、实际示例、注意事项几个方面讲清楚,新手也能轻松理解,最后还会总结核心要点。

一、map 是什么?

map 是 JavaScript 数组的高阶函数(接收函数作为参数的函数),核心作用是:遍历数组的每一个元素,对每个元素执行指定的处理函数,最后返回一个「新数组」,新数组的元素是原数组元素处理后的结果。

简单说:map 就是「数组的批量加工器」,不改变原数组,只返回加工后的新数组。

二、基本语法

array.map(function(currentValue,index,arr), thisValue) 
参数描述
function(currentValue, index,arr)必须。函数,数组中的每个元素都会执行这个函数
函数参数:
参数描述
currentValue必须。当前元素的值
index可选。当前元素的索引值
arr可选。当前元素属于的数组对象
thisValue可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。
如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。

返回值:返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
原数组.map(function(当前元素, 索引, 原数组) { // 对当前元素的处理逻辑 return 处理后的结果; // 必须有return,否则新数组元素为undefined }, 可选的this指向); // 更常用的箭头函数写法(简洁,推荐) 原数组.map((item, index, arr) => { return 处理后的结果; }); // 若处理逻辑只有一行,可省略大括号和return(箭头函数简写) 原数组.map(item => 处理后的结果);
参数说明(前 3 个是处理函数的参数,最常用前 2 个)
  1. item(必选):当前正在遍历的数组元素;
  2. index(可选):当前元素的索引(从 0 开始);
  3. arr(可选):调用 map 的原数组本身;
  4. 可选的 this 指向(极少用):指定处理函数内部 this 的指向(箭头函数不绑定 this,此参数对箭头函数无效)。

三、核心特性(重点)

  1. 返回新数组:不会修改原数组,纯函数特性(无副作用),这是和 for 循环直接修改原数组的核心区别;
  2. 长度不变:新数组的长度和原数组完全一致,哪怕某个元素处理后返回 undefined,新数组对应位置也会是 undefined
  3. 必须有 return:如果处理函数没有 return,新数组的所有元素都会是 undefined
  4. 遍历所有元素:不会跳过数组中的任何元素(包括 undefined/null)。

四、实际示例(从简单到复杂)

结合实际场景,看 map 的常用用法,对比传统 for 循环,能更直观感受到 map 的简洁性。

示例 1:基础用法 —— 数组元素翻倍

将数组中每个数字乘以 2,返回新数组。

// 原数组 const nums = [1, 2, 3, 4]; // map 处理 const newNums = nums.map(item => item * 2); console.log(原数组: nums); // 原数组: [1,2,3,4](未修改) console.log(新数组: newNums); // 新数组: [2,4,6,8]

对比 for 循环:需要手动创建空数组、遍历、push,代码更繁琐:

const nums = [1, 2, 3, 4]; const newNums = []; for (let i = 0; i < nums.length; i++) { newNums.push(nums[i] * 2); }

示例 2:使用索引 —— 给数组元素加索引标识

const fruits = ['苹果', '香蕉', '橙子']; // 结合index,生成「索引-水果」的新数组 const fruitList = fruits.map((item, index) => `${index+1}-${item}`); console.log(fruitList); // ["1-苹果", "2-香蕉", "3-橙子"]
示例 3:处理对象数组(开发最常用)

实际开发中,常遇到接口返回的对象数组,用 map 提取需要的属性,或加工对象属性,非常方便。

// 接口返回的用户数组(原数据) const users = [ { id: 1, name: '张三', age: 20 }, { id: 2, name: '李四', age: 25 }, { id: 3, name: '王五', age: 30 } ]; // 需求1:只提取所有用户的name,生成姓名数组 const userNames = users.map(item => item.name); console.log(userNames); // ["张三", "李四", "王五"] // 需求2:加工对象,给每个用户加「是否成年」的属性,返回新对象数组 const newUsers = users.map(item => ({ ...item, // 解构原对象,保留原有属性 isAdult: item.age >= 18 // 新增属性 })); console.log(newUsers); // 结果:[{id:1, name:'张三', age:20, isAdult:true}, ...]
注意:对象数组的简写中,返回对象需要加小括号(),否则 JS 会把大括号 {} 当作函数体,而非对象。
示例 4:省略 return 的坑

如果处理函数没有 return,新数组所有元素都是 undefined,一定要避免:

const nums = [1,2,3]; const badNums = nums.map(item => { item * 2 }); // 无return console.log(badNums); // [undefined, undefined, undefined]

示例 5:占位符

下划线 _ 来作为占位符

const newArr = arr.map((_, index) => index);

五、map 与 forEach 的区别(易混淆,必看)

很多新手会把 mapforEach 搞混,两者都能遍历数组,但核心区别是是否有返回值,适用场景不同:

特性mapforEach
返回值有,返回新数组无,返回 undefined
核心用途对数组元素做加工转换,需要新数组单纯的遍历执行操作(如打印、修改外部变量)
是否可链式调用可以(如 map ().filter ())不可以(无返回值)

示例对比:

const nums = [1,2,3]; // map:有返回值,可链式调用 nums.map(item => item*2).filter(item => item > 3); // [4,6] // forEach:无返回值,链式调用会报错 nums.forEach(item => item*2).filter(...) // Uncaught TypeError: Cannot read property 'filter' of undefined

六、注意事项

  1. 不修改原数组map 的设计初衷是纯函数,尽量不要在处理函数中修改原数组的元素(尤其是对象 / 数组元素,因为引用类型会浅拷贝,后续单独讲);
  2. 遍历不可中断map 会遍历数组所有元素,无法像 for 循环那样用 break/continue 中断遍历,如果需要中断,用 filter 先过滤,或直接用 for 循环;
  3. 浅拷贝:如果原数组是引用类型数组(对象 / 数组),map 返回的新数组中,元素是原对象的浅拷贝(即新数组和原数组指向同一个对象),修改新数组的对象属性,会影响原数组:
const arr = [{a: 1}]; const newArr = arr.map(item => item); newArr[0].a = 2; // 修改新数组的对象属性 console.log(arr[0].a); // 2(原数组也被修改了)
  • 解决:在 map 中返回新对象(如示例 3 的解构 ...item),实现深拷贝(简单场景)。

       4.避免空值遍历:如果数组中有空值(empty),map 会跳过,但仍会在新数组中保留空值位置:

const arr = [1, , 3]; // 中间有一个空值 const newArr = arr.map(item => item * 2); console.log(newArr); // [2, , 6]

总结

  1. map 是数组高阶函数,核心是遍历 + 加工 + 返回新数组,不修改原数组,长度和原数组一致;
  2. 语法上推荐箭头函数简写,处理函数必须有 return,否则新数组元素为 undefined
  3. 开发中最常用在加工普通数组提取 / 修改对象数组属性,比 for 循环更简洁;
  4. forEach 核心区别:map 有返回值(新数组)可链式调用,forEach 无返回值仅做遍历;
  5. 注意引用类型数组的浅拷贝问题,如需独立对象,在 map 中返回新对象即可。
Could not load content