Reduce技巧

作为加法器和累加器

使用“reduce”,我们可以轻松实现多个数相加或累加的功能。

const sum = (...nums) => {
    return nums.reduce((sum, num) => sum + num)
}

sum(1, 2, 3, 4, 10) // = 20

const accumulator = (...nums) => {
  return nums.reduce((acc, num) => acc * num)
}

accumulator(1, 2, 3) // = 6

计算一个数组的最大值和最小值

  1. 使用 Math.max 和 Math.min

我们不得不承认,使用 Math 的 API 是最简单的方法。

const arr = [0, 20, 3, 5]

Math.max(...arr) // = 20
Math.min(...arr) // = 0
  1. 使用减少
const arr = [0, 20, 3, 5]

arr.reduce((max, num) => (max > num ? max : num))
arr.reduce((min, num) => (min < num ? min : num))

格式化搜索参数

获取链接上的搜索参数是我们经常要处理的事情。如何解析它们?

// 例如
// url https://www.url.com/test?name=mkimq&age=18
// format the search parameters

{
    "name": "mkimq",
    "age": "18"
}
  1. 正常方式
const parseQuery = () => {
    const search = window.location.search
    let query = {}

    search
        .slice(1)
        .split("&")
        .forEach((it) => {
        const [key, value] = it.split("=");
        query[key] = decodeURIComponent(value);
        })

    return query
}
  1. 使用reduce
const parseQuery = () => {
    const search = window.location.search

    return search
        .replace(/(^\?)|(&$)/g, "")
        .split("&")
        .reduce((query, it) => {
        const [key, value] = it.split("=")
        query[key] = decodeURIComponent(value)
        return query
        }, {})
}

反序列化搜索参数

当我们要跳转到某个链接并为其添加一些搜索参数时,手动拼接的方式不是很方便。

如果要串联的参数很多,那将是一场灾难。

const searchObj = {
    name: 'mkimq',
    age: 18
}

const link = `https://www.url.com/test?name=${searchObj.name}&age=${searchObj.age}`

幸运的是,“reduce”可以帮助我们轻松解决这个问题。

const stringifySearch = (search = {}) => {
    return Object.entries(search)
        .reduce(
        (t, v) => `${t}${v[0]}=${encodeURIComponent(v[1])}&`,
        Object.keys(search).length ? "?" : ""
        )
        .replace(/&$/, "")
}

const search = stringifySearch({
    name: "mkimq",
    age: 18,
})

const link = `https://www.url.com/test${search}`

展平多层嵌套数组

你知道如何展平多层嵌套数组吗?

const array = [1, [2, [3, [4, [5]]]]]

array.flat(Infinity) // = [1, 2, 3, 4, 5]

“flat”是一个非常强大的API。

使用reduce实现和flat一样的功能。

const flat = (array) => {
    return array.reduce(
        (acc, it) => acc.concat(Array.isArray(it) ? flat(it) : it),
        []
    )
}

const array = [1, [2, [3, [4, [5]]]]]
flat(array) // = [1, 2, 3, 4, 5]

模拟平面特征的功能

虽然我们已经实现了扁平化深度嵌套数组的功能,但是如何才能完全实现扁平化的功能呢?

// Expand one layer by default
Array.prototype.flat2 = function (n = 1) {
    const len = this.length
    let count = 0
    let current = this
    if (!len || n === 0) {
        return current
    }
    // Confirm whether there are array items in current
    const hasArray = () => current.some((it) => Array.isArray(it))
    // Expand one layer after each cycle
    while (count++ < n && hasArray()) {
        current = current.reduce((result, it) => {
        result = result.concat(it)
        return result
        }, [])
    }
    return current
}
const array = [ 1, [ 2, [ 3, [ 4, [ 5 ] ] ] ] ]
// Expand one layer
array.flat() // = [ 1, 2, [ 3, [ 4, [ 5 ] ] ] ]
array.flat2() // = [ 1, 2, [ 3, [ 4, [ 5 ] ] ] ]
// Expand all
array.flat(Infinity)
array.flat2(Infinity)

保持数组唯一

reduce 也很容易保持数组的唯一性。

const array = [ 1, 2, 1, 2, -1, 10, 11 ]
const uniqueArray1 = [ ...new Set(array) ]
const uniqueArray2 = array.reduce((acc, it) => acc.includes(it) ? acc : [ ...acc, it ], [])

统计数组成员的个数

如何计算数组中每个成员的个数?

为什么使用地图而不是对象?

const count = (array) => {
    return array.reduce((acc, it) => (acc.set(it, (acc.get(it) || 0) + 1), acc), new Map())
}
const array = [ 1, 2, 1, 2, -1, 0, '0', 10, '10' ]
console.log(count(array))

获取一个对象的多个属性

朋友们,让我们来看看你在工作中会遇到的一个场景。

// There is an object with many properties
const obj = {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    e: 5
    // ...
}
// We just want to get some properties above it to create a new object
const newObj = {
    a: obj.a,
    b: obj.b,
    c: obj.c,
    d: obj.d
    // ...
}
// Do you think this is too inefficient?

使用reduce来解决它

const getObjectKeys = (obj = {}, keys = []) => {
    rn Object.keys(obj).reduce((acc, key) => (keys.includes(key) && (acc[key] = obj[key]), acc), {});
}
const obj = {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    e: 5
    // ...
}
const newObj = getObjectKeys(obj, [ 'a', 'b', 'c', 'd' ])
console.log(newObj)

反转字符串


const reverseString = (string) => {
    return string.split("").reduceRight((acc, s) => acc + s)
}
const string = 'fatfish'
reverseString(string) // = hsiftaf
贡献者: mankueng