开发人员每天面临的个实几乎所有问题都可以通过解决一组较小的问题来解决,针对单个明确定义的代码问题的小解决方案。这些解决方案可以最好地描述为“纯函数”。片段 尽管这些函数中的助成大多数是在不同的库中实现的,但重要的为更是要了解如何以及何时将困难的问题分解为更小的问题。这种解决问题的个实思维方式将提高我们的开发效率,并使我们成为更好的代码开发人员。 今天的片段文章中,我分享的助成是我经常用来解决各种问题的 20 个有用的“纯函数”的无序集合,希望对你也有用。为更 下面,个实我们开始吧。代码 给定一个对象或数组,助成函数将返回指定路径的为更值,否则为 null。 const getValue = (obj, path) => path .replace(/\[([^[\]]*)]/g, .$1.) .split(.) .filter(prop => prop !== ) .reduce((prev, next) => ( prev instanceof Object ? prev[next] : undefined ), obj); getValue({ a: { b: c: d } }, a.b.c); // = d 确保值在指定范围内,否则“clamp”到最接近的最小值和最大值。 const clamp = (min, max, value) => { if (min > max) throw new Error(min cannot be greater than max); return value < min ? min : value > max ? max : value; } } clamp(0, 10, -5); // = 0 在执行下一个操作之前等待指定的持续时间(以毫秒为单位)。 const sleep = async (duration) => ( new Promise(resolve => setTimeout(resolve, duration) ) ); 根据键控功能对对象中的相关项进行分组和索引。 const groupBy = (fn, list) => ( list.reduce((prev, next) => ({ ...prev, [fn(next)]: [...(prev[fn(next)] || []), next] }), { }) ); groupBy(vehicle => vehicle.make, [ { make: tesla, model: 3 }, { make: tesla, model: y }, { make: ford, model: mach-e }, ]); // { // tesla: [ { make: tesla, ... }, { make: tesla, ... } ], // ford: [ { make: ford, ... } ], 根据键控功能创建包含相关项目的子列表。 import groupBy from ./groupBy; const collectBy = (fn, list) => Object.values(groupBy(fn, list)); collectBy(vehicle => vehicle.make, [ { make: tesla, model: 3 }, { make: tesla, model: y }, { make: ford, model: mach-e }, ]); // [ // [ { make: tesla, ... }, { make: tesla, ... } ], // [ { make: ford, ... } ], 获取列表的第一个元素。这个函数对于编写干净易读的代码很有用。 const head = list => list[0]; head([1, 2, 3]); // = 1 获取列表中除第一个元素之外的所有元素。这个函数对于编写干净易读的代码很有用。 const tail = list => list.slice(1); tail([1, 2, 3]); // = [2, 3] 通过递归地从嵌套子列表中提取所有项目来创建一个平面列表。 const flatten = list => list.reduce((prev, next) => ([ ...prev, ...(Array.isArray(next) ? flatten(next) : [next]) ]), []); 查找键控函数定义的两个列表中存在的所有值。站群服务器 const intersectionBy = (fn, listA, listB) => { const b = new Set(listB.map(fn); return listA.filter(val => b.has(fn(val))); }; intersectionBy(v => v, [1, 2, 3], [2, 3, 4]); // = [2, 3] 通过键控函数确定的值对列表中的每个元素进行索引。 const indexBy = (fn, list) => list.reduce((prev, next) => ({ ...prev, [fn(next)]: next }, { }); indexBy(val => val.a, [{ a: 1 }, { a: 2 }, { a: 3 }]); 查找第一个列表中不存在于第二个列表中的所有项目,由键控功能确定。 import indexBy from ./indexBy; const differenceBy = (fn, listA, listB) => { const bIndex = indexBy(fn, listb); return listA.filter(val => !bIndex[fn(val)]); }); differenceBy(val => val, [1,2,3], [3,4,5]); // = [1,2] differenceBy( vehicle => vehicle.make, [{ make: tesla }, { make: ford }, { make: gm }], [{ make: tesla }, { make: bmw }, { make: audi }], 如果给定函数抛出错误,则返回默认值。 const recoverWith = async (defaultValue, fn, ...args) => { try { const result = await fn(...args); return result; } catch (_e) { return defaultValue; } } recoverWith(A, val => val, B); // = B 计算两点 p1 和 p2 之间的距离。 const distance = ([x0, y0], [x1, y1]) => ( Math.hypot(x1 - x0, y1 - y0) ); 从列表中删除元素,从第一个元素开始,直到满足 som 谓词。 const dropWhile = (pred, list) => { let index = 0; list.every(elem => { index++; return pred(elem); }); return list.slice(index-1); } 给定一些产生每个元素的单独值的函数,计算列表中所有元素的总和。 const sumBy = (fn, list) => list.reduce((prev, next) => prev + fn(next), 0); sumBy(product => product.price, [ { name: pizza, price: 10 }, { name: pepsi, price: 5 }, { name: salad, price: 5 }, 给定一个评估函数,创建一个升序比较器函数。 const ascending = (fn) => (a, b) => { const valA = fn(a); const valB = fn(b); return valA < valB ? -1 : valA > valB ? 1 : 0; } const byPrice = ascending(val => val.price); [{ price: 300 }, { price: 100 }, { price: 200 }].sort(byPrice); 给定一个评估函数,创建一个降序比较器函数。 const descending = (fn) => (a, b) => { const valA = fn(b); const valB = fn(a); return valA < valB ? -1 : valA > valB ? 1 : 0; } const byPrice = descending(val => val.price); [{ price: 300 }, { price: 100 }, { price: 200 }].sort(byPrice); 在满足给定predicate的索引中找到第一个键值。亿华云 const findKey = (predicate, index) => Object .keys(index) .find(key => predicate(index[key], key, index)); findKey( car => !car.available, { tesla: { available: true }, ford: { available: false }, gm: { available: true } }, 将给定列表的值拆分为两个列表,一个包含predicate函数评估为真值的值,另一个包含假值。 const bifurcateBy = (predicate, list) => list.reduce((acc, val, i) => ( acc[predicate(val, i) ? 0 : 1].push(val), acc), [[], []] ); bifurcateBy(val => val > 0, [-1, 2, -3, 4]); 执行从左到右的功能组合。所有额外的参数都将传递给列表中的第一个函数,因此可以有任何数量。结果将在第二个传递,第二个的结果将传递给第三个,……以此类推,直到处理完所有函数。 const pipe = (functions, ...args) => ( functions.reduce( (prev, next) => Array.isArray(prev) ? next(...prev) : next(prev), args ) ); pipe([Math.abs, Math.floor, val => -val], 4.20); // = -4 尽管所有这些功能对于帮助我们解决正在处理的问题非常有用,但最重要的是,我们要知道如何将复杂困难的问题进行分解,这样就可以独立解决每个明确的小问题。一旦你掌握了这个解决问题的小技巧,那么你已经在成为一名优秀的开发者的路上了! 如果你觉得我今天分享的内容对你有所帮助,请点赞我,关注我,同时,将这篇文章分享给你身边做开发的朋友,也许能够帮助到他。 最后,感谢你的阅读,祝编程愉快!1、服务器租用片段GetValue
2、Clamp
3、Sleep
4、GroupBy
5、Collect By
6、Head
7、Tail
8、Flatten
9、Intersection By
10、IndexBy
11、DifferenceBy
12、Recover With
13、Distance
14、Drop While
15、Sum By
16、升序
17、降序
18、Find Key
19、Bifurcate By
20、Pipe
最后的想法