JavaScript--reduce的简单使用

语法

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

参数

参数描述
function(total,currentValue, index,arr)必需。用于执行每个数组元素的函数。
函数参数:
参数描述
total必需。初始值, 或者计算结束后的返回值。
currentValue必需。当前元素
currentIndex可选。当前元素的索引
arr可选。当前元素所属的数组对象。
initialValue可选。传递给函数的初始值

eg:

let expr =  ['message','a']
let data = {
	message: {
		a: 1
	}
}
// 让data.message.a = 2
let b = expr.reduce((prev,next,currentIndex)=>{
    // 遍历到最后一层.xx时赋值给message.a = value
    if(currentIndex === expr.length-1){
        return prev[next] = 2;
    }
    return prev[next];
},data)
console.log(b)

最后b=>data.message.a的值就变成2了

常见的reduce现实应用:

1.  求和

function calcSum(...args) {
    const arr = [...args]
    let sum = 0;
    return arr.reduce((obj, cur) => {
        sum = obj + cur
        return sum
    }, sum)
}

求和思想也可以利用在二进制转十进制方法中:

// 小数部分 => 数字*(2的index次方)
function eachBinaryDigitPartToDecimal(binaryDigitPartArr) {
    return binaryDigitPartArr.map((currentValue, index) => {
        return Number(currentValue) * Math.pow(2, (-(index + 1)))
    })
}
// 如果该二进制只有整数部分则直接用 parseInt(string, radix) 处理
function eachBinaryIntPartToDecimal(binaryDigit) {
    return parseInt(binaryDigit, 2)
}

/**
* 将二进制小数(包含整数部分和小数部分)转换为十进制数
* @param binaryDigit 二进制数(可能是整数,也可能是小数)
*/
function floatToDecimal(binaryDigit) {
    // 如果该二进制只有整数部分则直接用 parseInt(string, radix) 处理
    if (Number.isInteger(binaryDigit)) {
        return eachBinaryIntPartToDecimal(binaryDigit)
    } else {
        // 将整数和小数部分的数字分开组成一个数组, 第一个元素是整数部分的数字, 第二个元素是小数部分的数字
        const binaryDigitNumArr = binaryDigit.toString().split(".")

        // 将二进制整数转换为十进制数
        const binaryIntParStr = binaryDigitNumArr[0]
        const decimalIntPartNum = eachBinaryIntPartToDecimal(binaryIntParStr)

        // 将二进制小数部分转换为十进制数
        const binaryDigitPartArr = binaryDigitNumArr[1].split("") // 将数字split成小数部分的每个数字作为元素的一元数组
        const eachDecimalFloatPartNum = eachBinaryDigitPartToDecimal(binaryDigitPartArr) // 数组的数字变成item * 2^(-index)
        const deciamlFloatPartNum = eachDecimalFloatPartNum.reduce((val, currentVal) => val + currentVal) // 数组元素相加
        return decimalIntPartNum + deciamlFloatPartNum
    }
}

console.log(floatToDecimal(1111011.111))  // 123.875
console.log(floatToDecimal(1111011))  // 123
console.log(floatToDecimal(0.111))  // 0.875

2. 将url的search参数转化为对象

const URL_SEARCH ='?source=baidupc_utmId_5100&plan=A005-qglrgmc&unit=a010-mp4&keyword=mp4zgif&keywordid=20210343653&bd_vid=7019318071742353099'
const urlObj = URL_SEARCH.slice(1) // 去掉第一个?号字符
.split('&')
.filter(Boolean)
.reduce((obj, cur)=> {
    let arr = cur.split('=')
    const idx = cur.indexOf('=') // 获取第一个=号所在的下标
    // if(arr.length !== 2) {
    //     return obj;
    // }
    obj[(cur.substring(0, idx))] = encodeURIComponent(cur.substring(idx+1));
    console.log(obj, cur)
    return obj;
}, {})
const getQueryString = (key) => urlObj[key]
console.log(getQueryString('unit'))

3. 让Promise依次执行

function runPromises(promiseCreators, initData) {// promiseCreators能够产生promise的数组
    return promiseCreators
        .reduce(
            (promise, next) => {
                return promise.then((data) => next(data))
            },
            Promise.resolve(initData)
        )
}


function login(data) {
    console.log("login: data", data);
    return new Promise(resolve => {
        setTimeout(() => {
            return resolve({
                token: 'token'
            })
        }, 500)
    })
}

function getUserInfo(data) {
    console.log("getUserInfo: data", data);
    return new Promise(resolve => {
        setTimeout(() => {
            return resolve({
                name: 'user-1',
                id: 988
            })
        }, 300)
    })
}

function getOrders(data) {
    console.log("getOrders: data", data);
    return new Promise(resolve => {
        setTimeout(() => {
            return resolve([{
                orderId: 1,
                productId: 100,
                price: 100
            }])
        }, 100)
    })
}

const initData = {
    name: 'nam1',
    pwd: 'pwd1'
}
runPromises([login, getUserInfo, getOrders],
    initData)
    .then(res => {
        console.log("res", res);
    })

相当于promise的链式调用:

// Promise.resolve(initData)
// .then(data => login(data))
// .then(data => getUserInfo(data))
// .then(data => getOrders(data))
// .then(data => console.log("orders", data))

4. 数组分组

function group(arr, fn) {
    // 不是数组
    if (!Array.isArray(arr)) {
        return arr
    }
    // 不是函数
    if (typeof fn !== 'function') {
        throw new TypeError('fn必须是一个函数')
    }
    var v
    return arr.reduce((obj, cur, index) => {
        v = fn(cur, index)
        if (!Reflect.hasOwnProperty.call(obj, v)) {
            obj[v] = []
        }
        obj[v].push(cur)
        return obj
    }, {})
}


// 按照字符串长度分组
let products = ["apple", "pear", "orange", "peach"];
const f1 = v => v.length
console.log(
    group(products, f1), 
);

// 按照分数分组
result = [{
    name: "tom",
    score: 60
}, {
    name: "Jim",
    score: 40
}, {
    name: "Nick",
    score: 88
}]
const fn = v => v.score >= 60

console.log(
    group(result, fn), 
);

5. 模拟compose, pipe方法:

const compose = (...funcs) => {
    if (funcs.length === 0) return arg => arg
    return funcs.reduce((v, cur) => (...args) => (v(cur(...args))))
}
// 注意: compose执行顺序就是从右往左依次传入的函数方法

const pipe = (...funcs) => {
    if (funcs.length === 0) return arg => arg
    return funcs.reduce((a, b) => (...args) => (b(a(...args))))
}
// pipe执行顺序是从左往右依次传入的传函数方法

例如几个优惠叠加计算:

// 九折优惠
function discount(x) {
    console.log('discount')
    return x * 0.9
}

// 满200减50
function reduce(x) {
    console.log('reduce')
    return x >= 200 ? x - 50 : x
}


// 优惠plus
const discountPlus = (x) => {
    console.log('discountPlus')
    return x * 0.95
}


const compose = (...funcs) => {
    if (funcs.length === 0) return arg => arg
    return funcs.reduce((v, cur) => (...args) => (v(cur(...args))))
}
// 先discount打折, 再reduce优惠, 再discountPlus打折
// compose执行顺序就是从后往前的
const getPrice = compose(discountPlus, reduce, discount)
print(getPrice(200), getPrice(250))


const pipe = (...funcs) => {
    if (funcs.length === 0) return arg => arg
    return funcs.reduce((a, b) => (...args) => (b(a(...args))))
}
// pipe参数从左往右依次传优惠
const getPrice2 = pipe(discount, reduce, discountPlus)
print(getPrice2(200), getPrice2(250))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值