搜索
首页web前端js教程用函数模板,写一个简单高效的 JSON 查询器的方法介绍_javascript技巧

JSON可谓是JavaScript的亮点,它能用优雅简练的代码实现Object和Array的初始化。同样是基于文本的数据定义,它比符号分隔更有语义,比XML更简洁。因此越来越多的JS开发中,使用它作为数据的传输和储存。

JS数组内置了不少有用的方法,方便我们对数据的查询和筛选。例如我们有一堆数据:

复制代码 代码如下:

var heros = [
        // 名============攻=====防=======力量====敏捷=====智力====
        {name:'冰室女巫', DP:38, AP:1.3, Str:16, Agi:16, Int:21},
        {name:'沉默术士', DP:39, AP:1.1, Str:17, Agi:16, Int:21},
        {name:'娜迦海妖', DP:51, AP:6.0, Str:21, Agi:21, Int:18},
        {name:'赏金猎人', DP:39, AP:4.0, Str:17, Agi:21, Int:16},
        {name:'剧毒术士', DP:45, AP:3.1, Str:18, Agi:22, Int:15},
        {name:'光之守卫', DP:38, AP:1.1, Str:16, Agi:15, Int:22},
        {name:'炼金术士', DP:49, AP:0.6, Str:25, Agi:11, Int:25}
        //...
    ];

要查询攻击大于40并且防御小于4的英雄,我们可以用Array的filter方法:

复制代码 代码如下:

 var match = heros.filter(function(e) {
        return e.DP > 40 && e.AP     });

返回得到一个数组,包括符合条件的2个结果。

相比手工去写循环判断,filter方法为我们提供了很大的方便。但它是基于函数回调的,所以每次使用必须写一个function,对于简单的查询很是累赘,而且使用回调效率也大大降低。但这是也没有办法的,想简单必然要牺牲一定性能。 如果能使用比这更简单的语句,并且完全拥有代码展开时效率,该有是多么完美的事。

先来想象下,要是能将上面的代码写成这样,并且查询速度和手写的遍历判断一样

复制代码 代码如下:

    var match = heros.select('@DP>40 AND @AP

看上去有点像SQL,连语法都换了?这样岂不是要写一个词法分析,语义解释等等等等一大堆的脚本引擎的功能了,没个几千上万行代码都搞不定,而且效率肯定更糟了。。。如果想到那么复杂,那么你还没深刻的理解脚本的精髓。但凡是脚本语言,都有运行时动态解释代码的接口,例如vbs的execute();js的eval(),new Function(),甚至创建一个<script>动态写入代码。 <P><STRONG>显然,要是能将另一种语言,翻译成js代码,那么就可直接交给宿主来执行了! <P>例如上面select中的字符,我们简单的将"@"替换成"e.", "AND"替换成"&&",于是就成了一个合法的js表达式,完全可以交给eval来执行。 <P>所以我们要做的,就是将原始语句翻译成js语句来执行。并且为了提高效率,将翻译好的js表达式内联到一个上下文环境,生成一个可执行的函数体,而不是每次遍历中都依靠回调来判断。 <P>于是,函数模版就要派上用场了。 <P><STRONG>函数模版简介<br><br>在C++里面,有宏和类模版这么个东西,可以让一些计算在编译阶段就完成了,大幅提升了运行时代码的性能。脚本虽然没有严格意义上的编译,但在第一次执行的时候会解析并充分的优化,这是目前主流浏览器相互竞争点。所以,我们要将重复eval的代码,镶嵌到事先提供的样板函数里:一个准备就绪,就差表达式计算的函数:<BR><div class="codetitle"><span><a style="CURSOR: pointer" data="84492" class="copybut" id="copybut84492" onclick="doCopy('code84492')"><U>复制代码 代码如下:<div class="codebody" id="code84492"><BR> /**<BR> * 模版: tmplCount<BR> * 功能: 统计arr数组中符合$express表达式的数量<BR> */<BR> function tmplCount(arr) {<BR> var count = 0; <P> for(var i = 0; i < arr.length; i++) {<BR> var e = arr[i]; <P> if($express) {<BR> count++;<BR> }<BR> }<BR> return count;<BR> }<BR><BR>上面就是一个模板函数,遍历参数arr[]并统计符合$express的数量。除了if(...)内的表达式外,其他都已经准备就绪了。字符$express也可以换成其他标识,只要不和函数内其他字符冲突即可。 <P>当我们需要实例化时,首先通过tmplCount.toString()将函数转成字符串格式,然后将其中的$express替换成我们想要的表达式,最后eval这串字符,得到一个Function类型的变量,一个模板函数的实例就产生了! <P><STRONG>我们简单的演示下:<BR><div class="codetitle"><span><a style="CURSOR: pointer" data="65929" class="copybut" id="copybut65929" onclick="doCopy('code65929')"><U>复制代码 代码如下:<div class="codebody" id="code65929"><BR> /**<BR> * 函数: createInstance<BR> * 参数: exp<BR> * 一段js表达式字符串,用来替换tmplCount模板的$express<BR> * 返回:<BR> * 返回一个Function,模版tmplCount的实例<BR> */<BR> function createInstance(exp)<BR> {<BR> // 替换模板内的表达式<BR> var code = tmplCount.toString()<BR> .replace('$express', exp);<br><br> // 防止匿名函数直接eval报错<BR> var fn = eval('0,' + code); <P> // 返回模板实例<BR> return fn;<BR> } <P><BR> // 测试参数<BR> var student = [<BR> {name: 'Jane', age: 14},<BR> {name: 'Jack', age: 20},<BR> {name: 'Adam', age: 18}<BR> ]; <P> // demo1<BR> var f1 = createInstance('e.age<16');<BR> alert(f1(student)); //1个 <P> // demo2<BR> var f2 = createInstance('e.name!="Jack" && e.age>=14');<BR> alert(f2(student)); //2个<BR><BR>注意createInstance()的参数中,有个叫e的对象,它是在tmplCount模版中定义的,指代遍历时的具体元素。返回的f1,f2就是tmplCount模板的两个实例。最终调用的f1,f2函数中,已经内嵌了我们的表达式语句,就像我们事先写了两个同样功能的函数一样,所以在遍历的时候直接运行表达式,而不用回调什么的,效率大幅提升。 <P><img src="/static/imghwm/default1.png" data-src="http://files.jb51.net/file_images/article/201304/201304171146157.png" class="lazy" alt=""> <P>其实说白了,tmplCount的存在仅仅是为了提供这个函数的字符串而已,其本身从来不会被调用。事实上用字符串的形式定义也一样,只不过用函数书写比较直观,方便测试。 <P>值得注意的是,如果脚本后期需要压缩优化,那么tmplCount模板绝对不能参与,否则对应的"e."和"$express"都有可能发生变化。 <P><STRONG>JSON基本查询功能 <P>函数模板的用处和实现介绍完了,再来回头看之前的JSON查询语言。我们只需将类似sql的语句,翻译成js表达式,并且生成一个函数模板实例。对于相同的语句,我们可以进行缓存,避免每次都翻译。 <P><STRONG>首先我们实现查询器的模板:<BR><div class="codetitle"><span><a style="CURSOR: pointer" data="48175" class="copybut" id="copybut48175" onclick="doCopy('code48175')"><U>复制代码 代码如下:<div class="codebody" id="code48175"><BR> var __proto = Object.prototype; <P> //<BR> // 模板: __tmpl<BR> // 参数: $C<BR> // 说明: 记录并返回_list对象中匹配$C的元素集合<BR> //<BR> var __tmpl = function(_list) {<BR> var _ret = [];<BR> var _i = -1; <P> for(var _k in _list) {<BR> var _e = _list[_k];<br><br> if(_e && _e != __proto[_k]) {<BR> if($C)<BR> _ret[++_i] = _e;<BR> }<BR> }<BR> return _ret; <P> }.toString();<BR><BR><STRONG>然后开始写Object的select方法:<BR><div class="codetitle"><span><a style="CURSOR: pointer" data="74878" class="copybut" id="copybut74878" onclick="doCopy('code74878')"><U>复制代码 代码如下:<div class="codebody" id="code74878"><BR> //<BR> // select方法实现<BR> //<BR> var __cache = {};<br><br> __proto.select = function(exp) {<BR> if(!exp)<BR> return []; <P> var fn = __cache[exp]; <P> try {<BR> if(!fn) {<BR> var code = __interpret(exp); //解释表达式<BR> code = __tmpl.replace('$C', code); //应用到模版 <P> fn = __cache[exp] = __compile(code); //实例化函数<BR> } <P> return fn(this); //查询当前对象<BR> }<BR> catch(e) {<BR> return [];<BR> }<BR> }<BR><BR>其中__cache表实现了查询语句的缓存。对于重复的查询,性能可以极大的提升。<BR><div class="codetitle"><span><a style="CURSOR: pointer" data="94768" class="copybut" id="copybut94768" onclick="doCopy('code94768')"><U>复制代码 代码如下:<div class="codebody" id="code94768"><BR> function __compile() {<BR> return eval('0,' + arguments[0]);<BR> }<BR><BR> __compile之所以单独写在一个空函数里,就是为了eval的时候有个尽可能干净的上下文环境。 <P>__interpret是整个系统的重中之重,负责将查询语句翻译成js语句。它的实现见智见仁,但尽可能简单,不要过度分析语法。 <P>具体代码查看:<A href="http://xiazai.jb51.net/201304/yuanma/jsonselect.rar" target=_blank>jsonselect.rar<BR>出于演示,目前只实现部分基本功能。以后还可以加上 LIKE,BETWEEN,ORDER BY 等等常用的功能。 <P><STRONG>Demo<BR><div class="codetitle"><span><a style="CURSOR: pointer" data="75283" class="copybut" id="copybut75283" onclick="doCopy('code75283')"><U>复制代码 代码如下:<div class="codebody" id="code75283"><BR>var heros = [<BR> // 名============攻=====防=======力量====敏捷=====智力====<BR> {name:'冰室女巫', DP:38, AP:1.3, Str:16, Agi:16, Int:21},<BR> {name:'沉默术士', DP:39, AP:1.1, Str:17, Agi:16, Int:21},<BR> {name:'娜迦海妖', DP:51, AP:6.0, Str:21, Agi:21, Int:18},<BR> {name:'赏金猎人', DP:39, AP:4.0, Str:17, Agi:21, Int:16},<BR> {name:'剧毒术士', DP:45, AP:3.1, Str:18, Agi:22, Int:15},<BR> {name:'光之守卫', DP:38, AP:1.1, Str:16, Agi:15, Int:22},<BR> {name:'炼金术士', DP:49, AP:0.6, Str:25, Agi:11, Int:25}<BR> //...<BR> ];<BR><BR><div class="codetitle"><span><a style="CURSOR: pointer" data="60993" class="copybut" id="copybut60993" onclick="doCopy('code60993')"><U>复制代码 代码如下:<div class="codebody" id="code60993"><BR> // 查询:力量,敏捷 都超过20的<BR> // 结果:娜迦海妖<BR> var match = heros.select('@Str>20 AND @Agi>20'); <P> // 查询:“士”结尾的<BR> // 结果:沉默术士,剧毒术士,炼金术士<BR> var match = heros.select('right(@name,1)="士" '); <P> // 查询:生命值 超过500的<BR> // 结果:炼金术士<BR> var match = heros.select('100 + @Str*19 > 500');<BR><BR> </script>
声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
了解JavaScript引擎:实施详细信息了解JavaScript引擎:实施详细信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python vs. JavaScript:学习曲线和易用性Python vs. JavaScript:学习曲线和易用性Apr 16, 2025 am 12:12 AM

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python vs. JavaScript:社区,图书馆和资源Python vs. JavaScript:社区,图书馆和资源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C到JavaScript:所有工作方式从C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器