跳到主要内容

Array.prototype.flatMap

// Array.prototype.flatMap ES2020
const arr = ['123', '456', '678'];

// 使用 map 和 flat 方法实现平铺
const newArr1 = arr
.map(function (item) {
return item.split('');
})
.flat();

console.log(newArr1);

等同于

mapflat 结合使用,实际上可以通过 flatMap 一步完成。这种方式的效率更高,因为它避免了对数组的多次遍历。ECMA-262MDN 都有提到这种性能差异。

const newArr2 = arr.flatMap(function (item) {
return item.split('');
});

console.log(newArr2);

参数

flatMap 接受一个回调函数和一个可选的 this 指向作为参数。

// 参数说明:
// 1. 当前遍历的元素
// 2. 当前遍历的元素在数组中的索引
// 3. 数组本身
// flatMap 的第二个参数可以修改回调函数的 `this` 指向
const arr = ['123', '456', '678'];

const newArr3 = arr.flatMap(
function (item, index, arr) {
console.log(item, index, arr);
console.log(this); // 显示 `this` 的值
},
{ a: 1 }
);

在上述代码中,this 被绑定为 { a: 1 },回调函数中 this 的值会被输出。


应用场景

拆解英文句子

如果你需要将英文句子按单词进行拆分,可以使用 flatMap,它将每个句子按空格拆分为单个单词,并将其平铺到一个数组中。

const arr = ["My name's SMC", "I'm 35", 'years old.'];

const newArr = arr.flatMap(function (item) {
return item.split(' '); // 使用空格拆分每个句子
});

console.log(newArr);
// ['My', "name's", 'SMC', "I'm", '35', 'years', 'old.']

遍历时增加项

在处理数组时,如果你希望对负数进行特殊处理,可以通过 flatMap 在遍历时增加额外的项。比如,将负数与前一个元素相加。

const arr = [1, -2, -3, 5, 8, -9, 6, 7, 0];

const newArr = arr.flatMap(function (item, index) {
if (item < 0 && index >= 1) {
return [item, `${item} + ${arr[index - 1]} = ${item + arr[index - 1]}`];
}
return item;
});

console.log(newArr);
// [1, -2, '-2+1 = -1', -3, '-3+-2 = -5', 5, 8, -9, '-9+8 = -1', 6, 7, 0]

在这个例子中,负数会与前一个数字相加,并以字符串的形式返回。


flatMap 方法实现

如果你希望自己实现类似 flatMap 的功能,可以按照以下步骤:

const arr = ['123', '456', '678'];

Array.prototype.myFlatMap = function (cb) {
// 判断回调函数是否有效
if (typeof cb !== 'function') {
throw new TypeError('Callback must be a function');
}

// 保存当前数组和传入的 this 值
var arr = this,
arg2 = arguments[1],
res = [],
item;

for (var i = 0; i < arr.length; i++) {
// 回调函数会使用 apply 方法绑定 this
item = cb.apply(arg2, [arr[i], i, arr]);

// 如果返回值为真,加入结果数组
if (item) {
res.push(item);
}
}

// 使用 flat 方法进行数组平铺
return res.flat();
};

const newArr = arr.myFlatMap(function (item) {
return item.split(''); // 将每个字符串拆分为字符数组
});

console.log(newArr);