电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

JavaScript Reduce使用詳解

瀏覽:121日期:2023-10-03 15:59:27

JavaScript Reduce使用詳解

學會這一個技巧 Reduce 讓你開啟編程新世界

Learning This Reduce Skill and a Whole New World Will Open up for You 🎉

reduce 可謂是 JS 數組方法最靈活的一個,因為可以替代數組的其他方法,比如 map / filter / some / every 等,也是最難理解的一個方法,lodash 很多方法也可以用其實現,學會 reduce 將給與開發者另一種函數式(Functional)、聲明式(Declarative)的視角解決問題,而不是以往的過程式(Procedual)或命令式(Imperative)

其中一個難點在于判斷 acc 即 accumulation 的類型以及如何選擇初始值,其實有個小技巧,可以幫助我們找到合適的初始值,我們想要的返回值的類型和 acc 類型需要是一樣的,比如求和最終結果是數字,則 acc 應該是數字類型,故其初始化必定是 0。

下面開始鞏固對 reduce 的理解和用法。

map

根據小技巧,map 最終返回值是數組,故 acc 也應該是一個數組,初始值使用空數組即可。

/** * Use `reduce` to implement the builtin `Array.prototype.map` method. * @param {any[]} arr * @param {(val: any, index: number, thisArray: any[]) => any} mapping * @returns {any[]} */function map(arr, mapping) { return arr.reduce((acc, item, index) => [...acc, mapping(item, index, arr)], []);}

測試

map([null, false, 1, 0, ’’, () => {}, NaN], val => !!val);// [false, false, true, false, false, true, false]filter

根據小技巧,filter 最終返回值也是數組,故 acc 也應該是一個數組,使用空數組即可。

/** * Use `reduce` to implement the builtin `Array.prototype.filter` method. * @param {any[]} arr * @param {(val: any, index: number, thisArray: any[]) => boolean} predicate * @returns {any[]} */function filter(arr, predicate) { return arr.reduce((acc, item, index) => predicate(item, index, arr) ? [...acc, item] : acc, []);}

測試

filter([null, false, 1, 0, ’’, () => {}, NaN], val => !!val);// [1, () => {}]some

some 當目標數組為空返回 false,故初始值為 false。

function some(arr, predicate) { return arr.reduce((acc, val, idx) => acc || predicate(val, idx, arr), false)}

測試:

some([null, false, 1, 0, ’’, () => {}, NaN], val => !!val);// truesome([null, false, 0, ’’, NaN], val => !!val);// false

附帶提醒,二者對結果沒影響但有性能區別,acc 放到前面因為是短路算法,可避免無謂的計算,故性能更高。

acc || predicate(val, idx, arr)

predicate(val, idx, arr) || accevery

every 目標數組為空則返回 true,故初始值為 true

function every(arr, predicate) { return arr.reduce((acc, val, idx) => acc && predicate(val, idx, arr), true)}findIndex

findIndex 目標數組為空返回 -1,故初始值 -1。

function findIndex(arr, predicate) { const NOT_FOUND_INDEX = -1; return arr.reduce((acc, val, idx) => { if (acc === NOT_FOUND_INDEX) { return predicate(val, idx, arr) ? idx : NOT_FOUND_INDEX; } return acc; }, NOT_FOUND_INDEX)}

測試

findIndex([5, 12, 8, 130, 44], (element) => element > 8) // 3pipe

一、實現以下函數

/** * Return a function to make the input value processed by the provided functions in sequence from left the right. * @param {(funcs: any[]) => any} funcs * @returns {(arg: any) => any} */function pipe(...funcs) {}

使得

pipe(val => val * 2, Math.sqrt, val => val + 10)(2) // 12

利用該函數可以實現一些比較復雜的處理過程

// 挑選出 val 是正數的項對其 val 乘以 0.1 系數,然后將所有項的 val 相加,最終得到 3const process = pipe( arr => arr.filter(({ val }) => val > 0), arr => arr.map(item => ({ ...item, val: item.val * 0.1 })), arr => arr.reduce((acc, { val }) => acc + val, 0));process([{ val: -10 }, { val: 20 }, { val: -0.1 }, { val: 10 }]) // 3

二、實現以下函數,既能實現上述 pipe 的功能,而且返回函數接納參數個數可不定

/** * Return a function to make the input values processed by the provided functions in sequence from left the right. * @param {(funcs: any[]) => any} funcs * @returns {(args: any[]) => any} */function pipe(...funcs) {}

使得以下單測通過

pipe(sum, Math.sqrt, val => val + 10)(0.1, 0.2, 0.7, 3) // 12

其中 sum 已實現

/** * Sum up the numbers. * @param args number[] * @returns {number} the total sum. */function sum(...args) { return args.reduce((a, b) => a + b);}參考答案一、返回函數接受一個參數

省略過濾掉非函數的 func 步驟

/** * Return a function to make the input value processed by the provided functions in sequence from left the right. * @param {(arg: any) => any} funcs * @returns {(arg: any) => any} */function pipe(...funcs) { return (arg) => { return funcs.reduce( (acc, func) => func(acc), arg ) }}二、返回函數接受不定參數

同樣省略了過濾掉非函數的 func 步驟

/** * Return a function to make the input value processed by the provided functions in sequence from left the right. * @param {Array<(...args: any) => any>} funcs * @returns {(...args: any[]) => any} */function pipe(...funcs) {// const realFuncs = funcs.filter(isFunction); return (...args) => { return funcs.reduce( (acc, func, idx) => idx === 0 ? func(...acc) : func(acc), args ) }}

性能更好的寫法,避免無謂的對比,浪費 CPU

function pipe(...funcs) { return (...args) => { // 第一個已經處理,只需處理剩余的 return funcs.slice(1).reduce( (acc, func) => func(acc), // 首先將特殊情況處理掉當做 `acc` funcs[0](...args) ) }}

第二種寫法的 funcs[0](...args) 這個坑要注意,數組為空就爆炸了,因為空指針了。

實現 lodash.get

實現 get 使得以下示例返回 ’hello world’。

const obj = { a: { b: { c: ’hello world’ } } };get(obj, ’a.b.c’);

函數簽名:

/** * pluck the value by key path * @param any object * @param keyPath string 點分隔的 key 路徑 * @returns {any} 目標值 */function get(obj, keyPath) {}參考答案

/** * Pluck the value by key path. * @param any object * @param keyPath string 點分隔的 key 路徑 * @returns {any} 目標值 */function get(obj, keyPath) { if (!obj) { return undefined; } return keyPath.split(’.’).reduce((acc, key) => acc[key], obj);}實現 lodash.flattenDeep

雖然使用 concat 和擴展運算符只能夠 flatten 一層,但通過遞歸可以去做到深度 flatten。

方法一:擴展運算符

function flatDeep(arr) { return arr.reduce((acc, item) => Array.isArray(item) ? [...acc, ...flatDeep(item)] : [...acc, item], [] )}

方法二:concat

function flatDeep(arr) { return arr.reduce((acc, item) => acc.concat(Array.isArray(item) ? flatDeep(item) : item), [] )}

有趣的性能對比,擴展操作符 7 萬次 1098ms,同樣的時間 concat 只能執行 2 萬次

function flatDeep(arr) { return arr.reduce((acc, item) => Array.isArray(item) ? [...acc, ...flatDeep(item)] : [...acc, item], [] )}var arr = repeat([1, [2], [[3]], [[[4]]]], 20);console.log(arr);console.log(flatDeep(arr));console.time(’concat’)for (i = 0; i < 7 * 10000; ++i) { flatDeep(arr)}console.timeEnd(’concat’)function repeat(arr, times) { let result = []; for (i = 0; i < times; ++i) { result.push(...arr) } return result; }過濾掉對象中的空值

實現

clean({ foo: null, bar: undefined, baz: ’hello’ })// { baz: ’hello’ }

答案

/** * Filter out the `nil` (null or undefined) values. * @param {object} obj * @returns {any} * * @example clean({ foo: null, bar: undefined, baz: ’hello’ }) * * // => { baz: ’hello’ } */export function clean(obj) { if (!obj) { return obj; } return Object.keys(obj).reduce((acc, key) => { if (!isNil(obj[key])) { acc[key] = obj[key]; } return acc; }, {});}enumify

將常量對象模擬成 TS 的枚舉

實現 enumify 使得

const Direction = { UP: 0, DOWN: 1, LEFT: 2, RIGHT: 3,};const actual = enumify(Direction);const expected = { UP: 0, DOWN: 1, LEFT: 2, RIGHT: 3, 0: ’UP’, 1: ’DOWN’, 2: ’LEFT’, 3: ’RIGHT’,};deepStrictEqual(actual, expected);

答案:

/** * Generate enum from object. * @see https://www.typescriptlang.org/play?#code/KYOwrgtgBAglDeAoKUBOwAmUC8UCMANMmpgEw5SlEC+UiiAxgPYgDOTANsAHQdMDmAChjd0GAJQBuRi3ZdeA4QG08AXSmIgA * @param {object} obj * @returns {object} */export function enumify(obj) { if (!isPlainObject(obj)) { throw new TypeError(’the enumify target must be a plain object’); } return Object.keys(obj).reduce((acc, key) => { acc[key] = obj[key]; acc[obj[key]] = key; return acc; }, {});}Promise 串行執行器

利用 reduce 我們可以讓不定數量的 promises 串行執行,在實際項目中能發揮很大作用。此處不細講,請參考我的下一篇文章 JS 請求調度器。

拓展

請使用 jest 作為測試框架,給本文的所有方法書寫單測更多習題見 github.com/you-dont-ne…

以上就是JavaScript Reduce使用詳解的詳細內容,更多關于JavaScript Reduce使用的資料請關注好吧啦網其它相關文章!

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 无锡门窗-系统门窗-阳光房-封阳台-断桥铝门窗厂[窗致美] | 浙江建筑资质代办_二级房建_市政_电力_安许_劳务资质办理公司 | 小港信息港-鹤壁信息港 鹤壁老百姓便民生活信息网站 | 船用烟火信号弹-CCS防汛救生圈-船用救生抛绳器(海威救生设备) | 铸铝门厂家,别墅大门庭院大门,别墅铸铝门铜门[十大品牌厂家]军强门业 | 楼梯定制_楼梯设计施工厂家_楼梯扶手安装制作-北京凌步楼梯 | 软膜天花_软膜灯箱_首选乐创品牌_一站式天花软膜材料供应商! | 保镖公司-私人保镖-深圳保镖公司【环宇兄弟保镖】 | 英国雷迪地下管线探测仪-雷迪RD8100管线仪-多功能数字听漏仪-北京迪瑞进创科技有限公司 | 九州网址_专注于提供网址大全分享推广中文网站导航服务 | 二氧化碳/活性炭投加系统,次氯酸钠发生器,紫外线消毒设备|广州新奥 | 12cr1mov无缝钢管切割-15crmog无缝钢管切割-40cr无缝钢管切割-42crmo无缝钢管切割-Q345B无缝钢管切割-45#无缝钢管切割 - 聊城宽达钢管有限公司 | 光纤测温-荧光光纤测温系统-福州华光天锐光电科技有限公司 | 全自动烧卖机厂家_饺子机_烧麦机价格_小笼汤包机_宁波江北阜欣食品机械有限公司 | 智能楼宇-楼宇自控系统-楼宇智能化-楼宇自动化-三水智能化 | 广东机电安装工程_中央空调工程_东莞装饰装修-广东粤标建设有限公司 | 清管器,管道清管器,聚氨酯发泡球,清管球 - 承德嘉拓设备 | TPE塑胶原料-PPA|杜邦pom工程塑料、PPSU|PCTG材料、PC/PBT价格-悦诚塑胶 | 厌氧工作站-通用型厌氧工作站-上海胜秋科学仪器有限公司 | 护栏打桩机-打桩机厂家-恒新重工| 橡胶粉碎机_橡胶磨粉机_轮胎粉碎机_轮胎磨粉机-河南鼎聚重工机械制造有限公司 | 袋式过滤器,自清洗过滤器,保安过滤器,篮式过滤器,气体过滤器,全自动过滤器,反冲洗过滤器,管道过滤器,无锡驰业环保科技有限公司 | 工业铝型材生产厂家_铝合金型材配件批发精加工定制厂商 - 上海岐易铝业 | 钢格板|镀锌钢格板|热镀锌钢格板|格栅板|钢格板|钢格栅板|热浸锌钢格板|平台钢格板|镀锌钢格栅板|热镀锌钢格栅板|平台钢格栅板|不锈钢钢格栅板 - 专业钢格板厂家 | 贵州自考_贵州自学考试网| 品牌策划-品牌设计-济南之式传媒广告有限公司官网-提供品牌整合丨影视创意丨公关活动丨数字营销丨自媒体运营丨数字营销 | 蓝米云-专注于高性价比香港/美国VPS云服务器及海外公益型免费虚拟主机 | 包头市鑫枫装饰有限公司| 洛阳网站建设_洛阳网站优化_网站建设平台_洛阳香河网络科技有限公司 | 浙江华锤电器有限公司_地磅称重设备_防作弊地磅_浙江地磅售后维修_无人值守扫码过磅系统_浙江源头地磅厂家_浙江工厂直营地磅 | 中开泵,中开泵厂家,双吸中开泵-山东博二泵业有限公司 | 常州减速机_减速机厂家_常州市减速机厂有限公司 | 哈希余氯测定仪,分光光度计,ph在线监测仪,浊度测定仪,试剂-上海京灿精密机械有限公司 | 武汉高低温试验箱_恒温恒湿试验箱厂家-武汉蓝锐环境科技有限公司 | 模具钢_高速钢_不锈钢-万利钢金属材料| 抖音短视频运营_企业网站建设_网络推广_全网自媒体营销-东莞市凌天信息科技有限公司 | 济南品牌设计-济南品牌策划-即合品牌策划设计-山东即合官网 | 液压中心架,数控中心架,自定心中心架-烟台恒阳机电设计有限公司 行星搅拌机,双行星搅拌机,动力混合机,无锡米克斯行星搅拌机生产厂家 | 冷热冲击试验箱_温度冲击试验箱价格_冷热冲击箱排名_林频厂家 | 电伴热系统施工_仪表电伴热保温箱厂家_沃安电伴热管缆工业技术(济南)有限公司 | 柴油机_柴油发电机_厂家_品牌-江苏卡得城仕发动机有限公司 |