数组对象常用的操作方法汇总

前言 曾看到过网上很多文章,一分钟了解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的仓库

数组对象的去重

数组对象的查找

数组对象的封装API

that's all, 以上是我自身的开发经验,如果我哪里写错了,希望能指点出来。如果你有更好的想法或者建议,可以提出来与我交流。大家一起进步,共同成长。感谢[鞠躬]。

参考来源:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值