最近这几天重新学习前端,在视频里面老师说了一个题:数组去重
,由于自己目前做后端,对数据比较敏感,基于此,写了此片文章来写一下自己目前写出来的一些方法:linq to js
什么叫linq
linq是C#
中的概念,具体用于处理集合和集合之间的关系,例如常见的where
、dinstinct
、union
、join
等
前端如何实现简单linq
前端由很出名的编程方式是函数式编程
,而linq的所有方法都以函数式编程
作为基础。
在new Function
没出来之前基本上不可能实现linq,只有一种方法能实现那就是eval
。但是new Function
横空出世,那么前端就可以借助该方法来变相实现了。
new Function用法
new Function
用于自定义函数实现,例如:
// new Function(...args, functionBody);
var func = new Function('a', 'return a');
func(1); // 1
复制代码
linq的参数
举个例子:array.orderby(r => r.id)
1、第一件事:取得内部lambda
表达式或函数的参数名,这样我们就可以根据参数名动态的对new Function
进行参数传递(由于new Function
的参数名和函数方法体绑定,所以这里需要取得参数名)
取得函数参数我们可以通过正则表达式进行:
function getParam(fn) {
if(typeof fn !== 'object' && typeof fn !== 'function' ) return;
const COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; // 注释
const DEFAULT_PARAMS = /=[^,)]+/mg; // 默认参数
const FAT_ARROWS = /=>.*$/mg; // 箭头函数特殊处理
let code = fn.prototype ? fn.prototype.constructor.toString() : fn.toString();
code = code
.replace(COMMENTS, '')
.replace(FAT_ARROWS, '')
.replace(DEFAULT_PARAMS, '');
let result = code.slice(code.indexOf('(') + 1, code.indexOf(')')).match(/([^\s,]+)/g);
return result === null ? [] :result;
}
复制代码
通过上述函数就可以求的一个函数的参数名集合
linq的函数处理
linq中我们如何实现自定义函数的执行结果呢。平常的方法如果直接执行的话是实现起来很困难。所以我们利用了new Function
特殊处理一下我们的函数
function buildExpression(func) {
let paramArr = getParam(func); // 拿到参数名
let param = paramArr.length > 0 ? paramArr[0] : 0;
let expression = new Function(param, 'return (' + func + ')'); // 得到表达式
return expression;
}
复制代码
上述函数执行时会得到一个如下的匿名函数:
function anonymious(param) {
return (func(param))
}
复制代码
这个匿名函数就能很好的解决参数名的自定义和函数执行问题
orederby
最终我们就只需要根据输入的表达式执行函数,完成特定逻辑即可。
Array.prototype.orderby = function (func) {
if (!isFunction(func) && func != null) {
throw new Error("func is not a function or null");
}
if (func == null || this.length == 0) {
return JSON.parse(JSON.stringify(this));
}
let _this = JSON.parse(JSON.stringify(this)); // 深克隆
let expression = buildExpression(func); // 形成表达式
let len = _this.length;
// 采用冒泡排序交换位置
for (let i = 0; i < len; i++) {
for (let j = 0; j < len - i - 1; j++) {
let _data_j = _this[j];
let _value_j = expression()(_data_j);
let _data_j_plus_1 = _this[j + 1];
let _value_j_plus_1 = expression()(_data_j_plus_1);
if (_value_j > _value_j_plus_1) {
var temp = _this[j];
_this[j] = _this[j + 1];
_this[j + 1] = temp;
}
}
}
return _this;
}
复制代码
对应测试如下:
let arr = [
{'id': 3, 'name': 'xxx'},
{ 'id': 1, 'name': 'xxx11' },
{ 'id': -1, 'name': 'xxx11' },
{ 'id': 4, 'name': 'xxx11' }
]
let newArr = arr.orderby(r => r.id);
console.log(newArr);
复制代码
执行结果如下:
where
Array.prototype.where = function (func) {
if (!isFunction(func) && func != null) {
throw new Error("func is not a function or null");
}
if (func == null || this.length == 0) {
return JSON.parse(JSON.stringify(this));
}
let expression = buildExpression(func);
let _retArr = [];
let len = this.length;
for (let i = 0; i < len; i++) {
let item = this[i];
if (expression()(item)) {
_retArr.push(JSON.parse(JSON.stringify(item)));
}
}
return _retArr;
}
复制代码
对应测试如下:
let arr = [
{'id': 3, 'name': 'xxx'},
{ 'id': 1, 'name': 'xxx11' },
{ 'id': -1, 'name': 'xxx11' },
{ 'id': 4, 'name': 'xxx11' }
]
let newArr = arr.where(r => r.id == 3);
console.log(newArr);
复制代码
执行结果如下:
distinct
Array.prototype.distinct = function (func) {
if (!isFunction(func) && func != null) {
throw new Error("func is not a function or null");
}
if (this.length == 0) {
return JSON.parse(JSON.stringify(this));
}
let _func = func == null ? r => r : func;
let len = this.length;
let expression = buildExpression(_func);
let _retMap = {};
let _retArr = [];
for (let i = 0; i < len; i++) {
let item = this[i];
let data = expression()(item);
if (!Object.prototype.hasOwnProperty.call(_retMap, data)) {
_retMap[data] = item;
_retArr.push(item);
}
}
return _retArr;
}
复制代码
对应测试如下:
let arr = [
{'id': 3, 'name': 'xxx'},
{ 'id': 1, 'name': 'xxx11' },
{ 'id': 1, 'name': 'xxx11' },
{ 'id': 4, 'name': 'xxx11' }
]
let newArr = arr.distinct(r => r.id);
console.log(newArr);
复制代码
执行结果如下:
结尾
linq还有其他很多方法,这里就不一一叙述了,只介绍了orderby
、distinct
、where
等方法。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END