JavaScript 数据操作工具包

2018-03-29 14:54:59 +08:00
 wm123450405

源码:

https://github.com/wm123450405/linqjs
https://gitee.com/wm123450405/linqjs (国内)

简介:

  • 对 JavaScript 中原生数组、对象进行扩展, 提供了一些对数据的操作方法.
  • 包括对数组结构、树形结构、对象结构等数据进行 查询,排序,连接,合并,分组,分段,转换,遍历 等一系列功能.
  • 可以用精炼和易懂的代码实现比较复杂的操作

案例:

let array = [ 'zhao', 'qian', 'sun', 'li', 'zhou', 'wu', 'zheng', 'wang' ]
//将上述数组按照字母长度进行排序, 字母长度一致的按照字母顺序倒序排序
console.log(array.asEnumerable().orderBy(str => str.length).thenByDescending().toArray());
//结果为
//wu,li,sun,zhou,zhao,wang,qian,zheng
//一些人
let magnus = { name: "Hedlund, Magnus" }, 
    terry = { name: "Adams, Terry" }, 
    charlotte = { name: "Weiss, Charlotte" };
//一些宠物
let barley = { name: "Barley", owner: "Adams, Terry" }, 
    boots = { name: "Boots", owner: "Adams, Terry" }, 
    whiskers = { name: "Whiskers", owner: "Weiss, Charlotte" }, 
    daisy = { name: "Daisy", owner: "Hedlund, Magnus" };
//一个包含所有 人 的数组
let people = [ magnus, terry, charlotte ];
//一个包含所有 宠物 的数组
let pets = [ barley, boots, whiskers, daisy ];

//这是一个一对多关系的两个数组
//需要显示出来所有的 人-宠物 的关系信息
//传统做法是
for (let p of people) {
    for (let pet of pets) {
        if (pet.owner === p.name) {
             console.log(`${ p.name } - ${ pet.name }`);
        }
    }
}

//使用我的工具是
//思想类似数据库查询(如下语句), 连接两个数组(表), 条件为 person 的 name 与 pet 的 owner 相等
//select person.name, pet.name from `people` as person join `pets` as pet on person.name = pet.owner
people.asEnumerable()
    .join(pets, (person, pet) =>`${ person.name} - ${ pet.name}`, 
        person => person.name, 
        pet => pet.owner)
    .forEach(res => console.log(res));
//这是一个树形结构
let tree = {
    value: 'a',
    children: [
        {
            value: 'b',  //此节点为 节点 c 与 节点 f 的最小公共祖先
            children: [
                { value: 'c' },
                {
                    value: 'd',
                    children: [
                        { value: 'e' },
                        { value: 'f' },
                        { value: 'g' },
                    ]
                }
            ]
        },
        { value: 'h', }
    ]
};

//获取一个树形的中多个节点的最小公共祖先
let root = tree.asEnumerable(node => node.children, node => node.value);
console.log(root.lowestAncestor('c', 'f')); //结果是 b

更多用法及案例 希望大家进入文档查看 http://wm123450405.oschina.io/linqjs/#/zh-cn

望大家多多关注 并给于意见和指导 谢谢

3085 次点击
所在节点    分享创造
19 条回复
wm123450405
2018-03-29 15:54:33 +08:00
一开始,在 ES5 的时代,我觉得 js 对数组的操作实在太繁琐了. 可能正是这种繁琐才有了像 underscore 这样优秀的 js 库的出现.

我本不是做前端出身的,我觉得其他语言对于数组或列表的操作要比 js 好用很多,提供了大量的方法和功能. 于是最早参考的 C#中的功能实现了一些方法.

后来,ES6 发布并普及开来,js 原生数组也增加了很多好用的功能,但是这还远远不够.

于是我又翻出了我的代码用 ES6 重写.这一次我又借鉴了另外一些语言中的部分特性,比如 php.我想我后面可能再会添加一些其他语言类似的功能,比如 Java 等.

后来我在 stackoverflow 中看到很多人对于树形结构的操作提了很多的问题,我像我的工具包应该要可以为他们提供帮助.于是在最新的几个版本中我加入了对树形结构的一些操作.

我想现在这个工具包应该算比较稳定了. 所以我发上来希望和大家交流交流. 也希望能学到更多的东西.
codermagefox
2018-03-29 16:22:11 +08:00
楼主你好,请问我能抄一个自己做实现吗?
per
2018-03-29 16:51:40 +08:00
@wm123450405 没看代码,不过你这个是在数据类型的 prototype 上修改的吗?
wm123450405
2018-03-29 17:01:08 +08:00
@per 是的 在 prototype 上做了扩展的
wm123450405
2018-03-29 17:01:35 +08:00
@codermagefox 可以啊 我也是造了一些轮子而已
codermagefox
2018-03-29 17:03:07 +08:00
@wm123450405 #5 准备看完 underscore 再来看你这个,然后自己撸个试试。感谢,已 star
per
2018-03-29 18:04:32 +08:00
@wm123450405 那我这里有个问题,比如一个数组是由一个类 A 实例化得到的,然后这个 A 也是继承于其他类,那当访问你的这个方法的时候会通过原型链一层层往上找,考虑过开销嘛?
crs0910
2018-03-29 18:17:59 +08:00
wm123450405
2018-03-29 18:38:15 +08:00
@per 不好意思 不是很明白你想表达的意思 你可以举例说明下嘛 我这里只是扩展了 Array 类 用 Array.prototype 的方式
wm123450405
2018-03-29 18:40:15 +08:00
@crs0910 你是让我看看 mootools 这个库吗? 如果你希望的只是类似 flatMap 这样的展开一个包含数组元素的数组 在我的库里是 selectMany
zenxds
2018-03-29 18:48:18 +08:00
改原生数组的原型后患无穷,ES 标准里的一些方法名那么奇怪就是因为当年 prototype.js 的遗留才不得不改名
wm123450405
2018-03-29 18:54:27 +08:00
@zenxds 我的库默认只会在 Array 上注册一个 asEnumerable 方法 用来获取一个 IEnumerable 对象进行后续操作 当然也可以开启对 Array 的直接扩展 主要看你有没有用到其他有冲突的库
per
2018-03-29 18:57:01 +08:00
@wm123450405 我表达的不是很清楚,你可以看一下 MDN 上的解释。不过还是给你点个星
per
2018-03-29 18:57:12 +08:00
wm123450405
2018-03-29 20:45:03 +08:00
@per 感谢你提供的信息. 我想我在编写这个库的时候并没有考虑这一层面的性能问题.
首先你分享的文章我不是特别的明白 我理解的大概含义 一般的 js 引擎会对已有的对象的属性查找进行优化 会将属性按照某种顺序排列在内存中 并生成一个身份(shape 或 structure ID) 如果修改 prototype 的话 会打乱这种顺序 导致原本可以快速查找属性的功能失效 造成性能损失
就你一共提出的问题 我想:
如果说因为原型链比较深导致其查找 property 比较慢的话 我想这个应该不容易避免 因为原型链的深度是受类型的继承关系的影响
如果是因为修改 prototype 导致 js 引擎在做优化时不能达到最佳性能的话 我目前也没有更好的解决办法
wm123450405
2018-03-29 22:28:40 +08:00
首先感谢各位的关注 如果大家发现有什么问题或者有什么希望加入的功能 欢迎大家在此回复 或者直接在 github/gitee 上提 issue 给我
raphaelsoul
2018-04-02 09:47:51 +08:00
拒绝修改原生数据类型的库:(
narcotics
2018-04-02 14:30:24 +08:00
lodash 的做法是用 _.chain 做一层包装,再实现链式操作,最后用 _.value 做"拆箱"

总之改变原生原型不是个好实践
wm123450405
2018-04-02 16:39:17 +08:00
回复 楼上 2 位
首先 我的库里目前只对原生对象扩展了 asEnumerable 一个方法. 就是尽量避免冲突
其次 库也支持 Enumerable(source)的方式获取一个和 source.asEnumerable()一样的结果, 类似 lodash 的 chain. 再使用 toArray 等方法生成最终结果.
当然 如果大家觉得修改原生原型的做法确实不合适 我想也我会在后面的版本中修改 /删除这种方式

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/442501

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX