Learning this skill Learning This One of the difficulties is to determine the type of Let's start by consolidating our understanding and usage of map According to the tips, the final return value of /** * 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)], []); } test map([null, false, 1, 0, '', () => {}, NaN], val => !!val); // [false, false, true, false, false, true, false] filter According to the tips, the final return value of /** * 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, []); } test filter([null, false, 1, 0, '', () => {}, NaN], val => !!val); // [1, () => {}] some function some(arr, predicate) { return arr.reduce((acc, val, idx) => acc || predicate(val, idx, arr), false) } test: some([null, false, 1, 0, '', () => {}, NaN], val => !!val); // true some([null, false, 0, '', NaN], val => !!val); // false As a reminder, the two have no effect on the result but have performance differences. Putting acc in front is a short-circuit algorithm, which can avoid unnecessary calculations and thus has higher performance. acc || predicate(val, idx, arr) and predicate(val, idx, arr) || acc every If function every(arr, predicate) { return arr.reduce((acc, val, idx) => acc && predicate(val, idx, arr), true) } findIndex If 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) } test findIndex([5, 12, 8, 130, 44], (element) => element > 8) // 3 pipe1. Implement the following functions /** * 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) {} Make pipe(val => val * 2, Math.sqrt, val => val + 10)(2) // 12 This function can be used to implement some more complex processing // Pick out the items whose val is positive, multiply their val by 0.1, then add up the val of all items, and finally get 3 const 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 2. Implement the following function, which can realize the function of the above pipe and return a function that accepts an indefinite number of parameters. /** * 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) {} Make the following single test pass pipe(sum, Math.sqrt, val => val + 10)(0.1, 0.2, 0.7, 3) // 12 Among them, /** * Sum up the numbers. * @param args number[] * @returns {number} the total sum. */ function sum(...args) { return args.reduce((a, b) => a + b); } Reference answer 1. Returning a function that accepts a parameterOmit the func step of filtering out non-functions /** * 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 ) } } 2. Returning functions accept indefinite parametersThe func step of filtering out non-functions is also omitted. /** * 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 ) } } Better writing performance, avoiding unnecessary comparisons and wasting CPU function pipe(...funcs) { return (...args) => { // The first one has been processed, only the remaining ones need to be processed return funcs.slice(1).reduce( (acc, func) => func(acc), // First handle the special case as `acc` funcs[0](...args) ) } } Pay attention to the pitfall of the second way of writing Implementing lodash.get Implementing const obj = { a: { b: { c: 'hello world' } } }; get(obj, 'abc'); Function signature: /** * pluck the value by key path * @param any object * @param keyPath string dot-separated key path* @returns {any} target value*/ function get(obj, keyPath) {} Reference answer/** * Pluck the value by key path. * @param any object * @param keyPath string dot-separated key path* @returns {any} target value*/ function get(obj, keyPath) { if (!obj) { return undefined; } return keyPath.split('.').reduce((acc, key) => acc[key], obj); } Implementing lodash.flattenDeepAlthough concat and spread operators can only flatten one layer, deep flattening can be achieved through recursion. Method 1: Spread operator function flatDeep(arr) { return arr.reduce((acc, item) => Array.isArray(item) ? [...acc, ...flatDeep(item)] : [...acc, item], [] ) } Method 2: concat function flatDeep(arr) { return arr.reduce((acc, item) => acc.concat(Array.isArray(item) ? flatDeep(item) : item), [] ) } Interesting performance comparison: the expansion operator takes 1098ms to execute 70,000 times, while concat can only execute 20,000 times in the same time. 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; } Filter out null values in an objectaccomplish clean({ foo: null, bar: undefined, baz: 'hello' }) // { baz: 'hello' } Answer /** * 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; }, {}); } enumifySimulate constant objects as TS enumerations Implement 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); Answer: /** * 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 Serial ExecutorBy using reduce, we can make an indefinite number of promises execute serially, which can play a big role in actual projects. I won’t go into details here, please refer to my next article JS Request Scheduler. expandPlease use jest as the testing framework and write unit tests for all the methods in this article. For more exercises, see github.com/you-dont-ne… The above is the detailed content of the detailed explanation of the use of JavaScript Reduce. For more information about the use of JavaScript Reduce, please pay attention to other related articles on 123WORDPRESS.COM! You may also be interested in:
|
<<: CentOS7 64-bit installation mysql graphic tutorial
>>: Packetdrill's concise user guide
Last year, the open letter was a huge hit, even a...
Table of contents 1. Using Set()+Array.from() 2. ...
Since I found that the push image always timed ou...
Related articles: 9 practical tips for creating we...
In order to efficiently meet requirements and avo...
Table of contents Data volume Anonymous and named...
JSON is a lightweight data exchange format that u...
Under Linux, if you download and install an appli...
Back in the Kernel 2.6 era, a new security system...
This article introduces the CSS scrollbar selecto...
Table of contents 1. Build Docker 2. Enter the co...
Disable right-click menu <body oncontextmenu=s...
1. Download MySQL 1.1 Download address https://do...
Table of contents 1. Vue listener array 2. Situat...
Utilize the browser's non- overflow:auto elem...