手机版

介绍用函数模板编写简单高效的JSON查询器的方法

时间:2021-11-21 来源:互联网 编辑:宝哥软件园 浏览:

JSON是JavaScript的亮点。它可以用优雅简洁的代码初始化对象和数组。它也是基于文本的数据定义,比符号分离更具语义,比XML更简洁。因此,越来越多的JS开发使用它作为数据传输和存储。JS Array内置了很多有用的方法,方便我们查询和过滤数据。比如我们有一堆数据:复制代码如下: var heros=[//name================攻击========防御======力量=====敏捷=====智力========={ name : '。Agi:16,int:21},{name: '消音器',DP:51,AP:6.0,str :17,agi:16,int336021},{name:' naga警报器',dp333661}。Str :21、agi :21、int :18}、{name3360 '赏金猎人'、DP:45、ap:4.0、str :17、agi :21、int :16}、{name: '剧毒作业。Ap:3.1,str :18,agi336022,int :15},{name:' light guard ',dp:38,ap:1.1,str :16,agi:15,int :22},DP:49,AP:0.6,Str:25,Agi:11,Int:25} //.];要查询攻击大于40防御小于4的英雄,我们可以使用Array的过滤方法:复制代码如下:VARMatch=heros.filter(函数(e){ return e . dp40e . ap4;});返回一个数组,包括2个满足条件的结果。与手工编写循环判断相比,过滤方法为我们提供了极大的便利。但是它是基于函数回调的,所以每次使用都要写一个函数,对于简单的查询来说比较繁琐,使用回调的效率大大降低。但是,没有办法做到这一点。想要简单,就必须牺牲一定的性能。如果我们能使用更简单的语句,并在代码扩展中有充分的效率,那将是完美的。想象一下,如果上面的代码可以这样写,查询速度和手写遍历判断一样:复制的代码如下:VARMATE=HEROS。SELECT ('@ DP40和@ AP4 ');看起来有点像SQL,连语法都变了?是不是需要写很多脚本引擎功能,比如词法分析,语义解释等。这是几千行代码无法处理的,效率肯定更差。如果你考虑到复杂性,你还没有深刻理解剧本的本质。但是,所有脚本语言都有在运行时动态解释代码的接口,比如vbs中的execute();Jseval(),新建Function(),甚至创建脚本动态编写代码。显然,如果你能把另一种语言翻译成js代码,就可以直接交给宿主执行了!例如,在select中的上述字符中,我们只需将“@”替换为“e .”、“AND”和“with”,这就变成了合法的js表达式,可以交给eval执行。所以我们要做的就是把原来的语句翻译成js语句并执行。为了提高效率,翻译后的js表达式被内联到一个上下文中,生成一个可执行的函数体,而不是依赖回调来判断每个遍历。因此,函数模板将派上用场。函数模板介绍在C语言中,有宏和类模板之类的东西,可以在编译阶段完成一些计算,大大提高运行时代码的性能。虽然脚本没有严格编译,但是在第一次执行的时候会进行解析和充分优化,这是目前主流浏览器之间的竞争点。因此,我们需要将重复eval的代码嵌入到预先提供的模板函数中:一个准备计算差异表达式的函数:复制代码的代码如下:/** *模板: tmplCount *函数:统计arr数组中满足$ express */函数tmplCount(arr){ var count=0;for(var I=0;一、长度;I){ var e=arr[I];if($ express){ count;} }返回计数;}以上是一个模板函数,它遍历参数arr[]并计算满足$express的数量。除了if(.).字符$express也可以用其他标识符替换,只要它不与函数中的其他字符冲突。

当我们需要实例化时,我们首先通过tmplCount.toString()将function转换成字符串格式,然后用我们想要的表达式替换$express,最后对字符串求值得到一个Function类型的变量,就产生了一个模板函数的实例!在我们的简单演示中,复制代码如下:/** *函数: createInstance *参数: exp *一个js表达式字符串,用来替换tmplCount模板的$express *。返回:*返回一个函数。模板tmplCount */函数的示例创建实例(exp){//替换表达式varcode=tmplcount.tostring()。替换模板中的(' $ express ',exp);//防止匿名函数通过eval直接报告错误。var fn=eval('0 ',代码);//返回模板实例返回fn;}//测试参数varstudent=[{name:' Jane ',age: 14},{name3360' jack ',age: 20},{name:' Adam ',age 3360 18 }];//demo 1 var f1=CreateInstance(' e . age 16 ');alert(f1(学生));//1//demo 2 var F2=create instance(' e . name!=‘杰克’e . age=14’;alert(f2(学生));//在createInstance()的2个参数中,有一个名为e的对象,它是在tmplCount模板中定义的,引用遍历时的具体元素。要返回f1,f2是tmplCount模板的两个实例。我们的表达式语句已经嵌入到了最后调用的f1和f2函数中,就像我们预先编写了两个函数相同的函数一样,这样我们就可以在遍历的时候直接运行表达式而不用回调,大大提高了效率。

说白了,tmplCount的存在只是为了提供这个函数的字符串,永远不会被调用。其实字符串形式的定义是一样的,只是用函数写更直观,测试更方便。值得注意的是,如果脚本后期需要压缩优化,那么tmplCount模板一定不能参与,否则对应的' e . '和' $express '可能会改变。在介绍了JSON基本查询函数模板的使用和实现之后,我们再来回顾一下之前的JSON查询语言。我们只需要将类似sql的语句翻译成js表达式并生成一个函数模板实例。对于同一个语句,我们可以缓存它,避免每次都翻译它。首先,我们实现查询器的模板:复制代码如下: var _ _ prototype=object . prototype;////template : __tmpl //参数: $C //描述:记录并返回_list对象//var _ _ tmpl=function(_ list){ var _ ret=[]中匹配$C的元素集;var _ I=-1;for(var _ k in _ list){ var _ e=_ list[_ k];if(_e _e!=_ _ proto[_ k]){ if($ C)_ ret[_ I]=_ e;} } return _ ret}.toString();然后开始编写Object的select方法:复制代码如下:////select方法实现//var _ _ cache={ };_ _ proto . select=function(exp){ if(!exp)return[];var fn=_ _ cache[exp];请尝试{ if(!fn){ var code=_ _解释器(exp);//解释表达式代码=_ _ tmpl . replace($ C),代码);//应用于模板fn=_ _缓存[exp]=_ _编译(代码);//实例化函数}返回fn(this);//查询当前对象} catch(e){ return[];} } _ _ cache表实现了查询语句的缓存。对于重复查询,性能可以大大提高。复制代码如下: function _ _ compile(){ return eval(' 0 ',参数[0]);之所以只在空函数中编写} __compile,是为了在评估过程中尽可能保持上下文环境的干净。_ _解释是整个系统的重中之重,负责将查询语句翻译成js语句。它的实现从智到仁是不一样的,但是要尽可能的简单,语法不要过度分析。具体代码视图:jsonselect.rar只实现了一些演示的基本功能。以后还可以添加LIKE、BETWEEN、ORDER BY等常用函数。Demo副本代码的代码如下: var heros=[//Name===========================Defense=======Strength====Agile======={ Name : '冰室女巫'。Int:21},{name: '消音器',dp:39,ap:1.1,str :17,agi:16,int:21},{name3360' naga警报器',dp:51,ap:1。Agi:21,int:18},{name: '赏金猎人',DP:45,AP:3.1,str:17,agi:21,int336016},{name: '毒术士',dp33366}。Str :18,agi :22,int :15},{name3360' light guard ',DP:49,ap:1.1,str :16,agi :15,int :22},{name:' alchemy。AP:0.6,Str:25,Agi:11,Int:25} //.];复制代码如下://查询:力量和敏捷都超过20//结果:娜迦魔女varmatch=heros。选择(' @ str20和@ agi 20 ');//查询://石末结果:消音器,剧毒术士,炼丹师,varmatch=heros。select ('right (@ name,1)=' Shi ' ');//查询:如果生命值超过500//结果:炼金术士varmatch=heros . select(' 100 @ str * 19 500 ');

版权声明:介绍用函数模板编写简单高效的JSON查询器的方法是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。