JavaScript Array.map() 的 5 种用途
首先与 forEach()
会改变操作数组不同,.map()
是一种 non-mutating(非变异) 方法,它创建一个新数组,而不是只对调用数组进行更改的 mutating(变异) 方法。
1. 对数组中的每项元素调用函数
这是最基本的用法,不多说。简单看下例子
let exampleArray = [2, 3, 4, 5, 6];
let doubleArray = exampleArray.map(item => item * 2)
console.log(exampleArray ); // [2, 3, 4, 5, 6]
console.log(doubleArray); // [4, 6, 8, 10, 12]
2.将字符串转换为数组
我们已知 .map()
属于 Array 原型。那么如何在使用它来处理字符串呢。这时候我们可以使用 .call()
方法。
JavaScript 中的所有内容都是对象,方法只是附加到这些对象的函数。.call()
允许我们利用另一个对象的上下文。 因此,我们将数组中的 .map()
上下文复制到字符串。
.call()
可以传递参数,要使用的上下文和“参数原始函数的参数”。
const name = "Chuloo"
const map = Array.prototype.map
const newName = map.call(name, eachLetter => {
return `${eachLetter}a`
})
console.log(newName) // ["Ca", "ha", "ua", "la", "oa", "oa"]
上面例子中,我们只是在 String 上使用 .map()
的上下文,并传递了 .map()
所期望的函数参数。
这类似于 String 的 .split()
方法,不过 .split()
方法只能在返回数组之前修改每个单独的字符串字符。
3. 在 JavaScript 库中用于渲染列表
在 React 这样的JS库中利用 map()
来渲染列表中的项目。这需要 JSX 语法,但是 .map() 方法包含在类似于 mustache 的 JSX 语法中。这是 React 组件的一个很好的例子。
import React from "react";
import ReactDOM from "react-dom";
const names = ["john", "sean", "mike", "jean", "chris"];
const NamesList = () => (
<div>
<ul>{names.map(name => <li key={name}> {name} </li>)}</ul>
</div>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<NamesList />, rootElement);
这是 React 中的一个简单的无状态组件,它使用列表渲染div。 使用 .map()
渲染单个列表项以迭代最初创建的 names 数组。 此组件使用 ReactDOM 渲染 ID为 root 的 DOM 元素 。
重新格式化数组对象
如何处理数组中的对象? .map()
可用于迭代数组中的对象,并以与传统数组类似的方式,修改每个单独对象的内容 并返回一个新数组。 这个修改是基于回调函数中返回的内容来完成的。这里有一个例子:
const myUsers = [
{ name: 'chuloo', likes: 'grilled chicken' },
{ name: 'chris', likes: 'cold beer' },
{ name: 'sam', likes: 'fish biscuits' }
]
const usersByFood = myUsers.map(item => {
const container = {};
container[item.name] = item.likes;
container.age = item.name.length * 10;
return container;
})
console.log(usersByFood);
// [{chuloo: "grilled chicken", age: 60}, {chris: "cold beer", age: 50}, {sam: "fish biscuits", age: 30}]
我们所做的就是使用括号和点符号简单地修改数组中的每个对象。这个用例可以用于在前端应用程序上保存或解析之前处理或压缩接收到的数据。
5.小技巧使用案例
生成新数组元素的 callback 函数,可以传三个参数:
currentValue – callback 的第一个参数,数组中正在处理的当前元素,最常用的参数。
index – callback 的第二个参数,数组中正在处理的当前元素的索引。
array – callback 的第三个参数,map 方法被调用的数组。
// 下面的语句返回什么呢:
["1", "2", "3"].map(parseInt);
// 你可能觉的会是[1, 2, 3]
// 但实际的结果是 [1, NaN, NaN]
// 通常使用parseInt时,只需要传递一个参数.
// 但实际上,parseInt可以有两个参数.第二个参数是进制数.
// 可以通过语句"alert(parseInt.length)===2"来验证.
// map方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素,
// 元素索引, 原数组本身.
// 第三个参数parseInt会忽视, 但第二个参数不会,也就是说,
// parseInt把传过来的索引值当成进制数来使用.从而返回了NaN.
function returnInt(element) {
return parseInt(element, 10);
}
['1', '2', '3'].map(returnInt); // [1, 2, 3]
// 意料之中的结果
// 也可以使用简单的箭头函数,结果同上
['1', '2', '3'].map( str => parseInt(str) );
// 一个更简单的方式:
['1', '2', '3'].map(Number); // [1, 2, 3]
// 与`parseInt` 不同,下面的结果会返回浮点数或指数:
['1.1', '2.2e2', '3e300'].map(Number); // [1.1, 220, 3e+300]
还有一个非常实用的小技巧,像 .map() ,.reduce(), .filter() 这些方法支持链式调用。例如:
var myArr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var result = myArr
.map(function(element) {
// 数值大于5的数值视为5
if (element > 5)
return 5;
return element;
})
.reduce(function(prev, element) {
// 与之前的数值加总,回传后代入下一轮的处理
return prev + element;
}, 0);
// 40
console.log(result);
等同于
var myArr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
let result = myArr.map(m => m>5 ? 5 : m).reduce((x,y) => x+y);
console.log(result); // 40