后端重新学习前端之举一反三

最近这几天重新学习前端,在视频里面老师说了一个题:数组去重,由于自己目前做后端,对数据比较敏感,基于此,写了此片文章来写一下自己目前写出来的一些方法:linq to js

什么叫linq

linq是C#中的概念,具体用于处理集合和集合之间的关系,例如常见的wheredinstinctunionjoin

前端如何实现简单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);
复制代码

执行结果如下:

image.png

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);
复制代码

执行结果如下:

image.png

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);
复制代码

执行结果如下:

image.png

结尾

linq还有其他很多方法,这里就不一一叙述了,只介绍了orderbydistinctwhere等方法。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享