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>

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

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

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

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

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

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

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

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


热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

Atom编辑器mac版下载
最流行的的开源编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

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

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器