前言 曾看到过网上很多文章,一分钟了解ES6,30分钟掌握ES6,里面都是会讲到let,const解决闭包,箭头函数等等基础的API用法。实际上在ES6的使用过程中,我们除了要掌握基础的API外,更需要会灵活运用或者组合这些API来封装一些方法,解决我们项目中遇到的各种问题。下面我将用30-seconds-code中的ES6代码,替换lodash中数组对象常用的几种方法,一起来学习一下ES6的正确使用方式。
注意点:数组对象跟数组的操作唯一不同的地方在于,涉及数组对象的操作都要进行key值的指定。
Math
1. maxBy: 返回最大值
lodash
var objects = [{ 'n': 1 }, { 'n': 2 }];
_.maxBy(objects, function(o) { return o.n; });
// => { 'n': 2 }
// The `_.property` iteratee shorthand.
_.maxBy(objects, 'n');
// => { 'n': 2 }
复制代码
ES6
const maxBy = (arr, fn) => Math.max(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
maxBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 8
maxBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 8
复制代码
2. meanBy: 返回平均值
lodash
var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
_.meanBy(objects, function(o) { return o.n; });
// => 5
// The `_.property` iteratee shorthand.
_.meanBy(objects, 'n');
// => 5
复制代码
ES6
const averageBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) /
arr.length;
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 5
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 5
复制代码
3.minBy: 返回最小值
lodash
var objects = [{ 'n': 1 }, { 'n': 2 }];
_.minBy(objects, function(o) { return o.n; });
// => { 'n': 1 }
// The `_.property` iteratee shorthand.
_.minBy(objects, 'n');
// => { 'n': 1 }
复制代码
ES6
const minBy = (arr, fn) => Math.min(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
minBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 2
minBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 2
复制代码
4.sumBy:返回总和
lodash
var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
_.sumBy(objects, function(o) { return o.n; });
// => 20
// The `_.property` iteratee shorthand.
_.sumBy(objects, 'n');
// => 20
复制代码
ES6
const sumBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0);
复制代码
Array
1.differenceBy: 返回一个新数组,这个数组中的值,为排除了给定数组后的值。
lodash
_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
// => [3.1, 1.3]
// The `_.property` iteratee shorthand.
_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
// => [{ 'x': 2 }]
复制代码
ES6
const differenceBy = (a, b, fn) => {
const s = new Set(b.map(v => fn(v)));
return a.filter(x => !s.has(fn(x)));
};
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1.2]
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [ { x: 2 } ]
复制代码
2.intersection: 返回一个新数组,这个数组为传入数组交集元素组成的新数组;
lodash
_.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor);
// => [2.1]
// The `_.property` iteratee shorthand.
_.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
// => [{ 'x': 1 }]
复制代码
ES6
const intersectionBy = (a, b, fn) => {
const s = new Set(b.map(x => fn(x)));
return a.filter(x => s.has(fn(x)));
};
intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [2.1]
intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], v=> v.x); // => [{ 'x': 1 }]
复制代码
3.pullAllBy 改变源数组,移除数组中指定的数组对象
lodash
// 注意点: 不同于_.differenceBy, 这个方法会改变数组 array。
var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
_.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
console.log(array);
// => [{ 'x': 2 }]
复制代码
ES6
// 注意点: 不同于differenceBy, 这个方法会改变数组 array。
const pullBy = (arr, ...args) => {
const length = args.length;
let fn = length > 1 ? args[length - 1] : undefined;
fn = typeof fn == 'function' ? (args.pop(), fn) : undefined;
let argState = (Array.isArray(args[0]) ? args[0] : args).map(val => fn(val));
let pulled = arr.filter((v, i) => !argState.includes(fn(v)));
arr.length = 0;
pulled.forEach(v => arr.push(v));
};
var myArray = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }];
pullBy(myArray, [{ x: 1 }, { x: 3 }], o => o.x); // myArray = [{ x: 2 }]
复制代码
4.sortedIndexBy: 返回索引值,使用二进制的方式检索来决定,应该插入到数组中尽可能小的索引位置.
lodash
var objects = [{ 'x': 4 }, { 'x': 5 }];
_.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
// => 0
// The `_.property` iteratee shorthand.
_.sortedIndexBy(objects, { 'x': 4 }, 'x');
// => 0
复制代码
ES6
const sortedIndexBy = (arr, n, fn) => {
const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
const val = fn(n);
const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el)));
return index === -1 ? arr.length : index;
};
sortedIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 0
复制代码
5.unionBy: 返回一个新数组,数组的并集,按顺序返回,返回数组的元素是唯一的。
lodash
_.unionBy([2.1], [1.2, 2.3], Math.floor);
// => [2.1, 1.2]
// The `_.property` iteratee shorthand.
_.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
// => [{ 'x': 1 }, { 'x': 2 }]
复制代码
ES6
const unionBy = (a, b, fn) => {
const s = new Set(a.map(v => fn(v)));
return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))]));
};
unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], v => v.x); // => [{ 'x': 1 }, { 'x': 2 }]
复制代码
总结
为什么选择数组对象来讲?因为我们在项目中碰到的最多的数据格式不是数组,也不是对象,而是数组对象(尤其是开发后台管理系统的程序员)。
在项目中我们对数组对象的处理需求是经常会出现的,如何快速解决数组对象的重组处理?这是一个问题,下面是我结合30-seconds-code以及自身开发经验整理出来的数组对象常用的方法代码库,减少重复踩坑,相信会对你的开发带来一点帮助吧。
代码库1
代码库2
更多资料,请移步star heightzhang的仓库
that's all, 以上是我自身的开发经验,如果我哪里写错了,希望能指点出来。如果你有更好的想法或者建议,可以提出来与我交流。大家一起进步,共同成长。感谢[鞠躬]。
参考来源: