Rumah hujung hadapan web tutorial js 用函数模板,写一个简单高效的 JSON 查询器的方法介绍_javascript技巧

用函数模板,写一个简单高效的 JSON 查询器的方法介绍_javascript技巧

May 16, 2016 pm 05:36 PM
json

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/imghw/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>
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Gabungan golang WebSocket dan JSON: merealisasikan penghantaran dan penghuraian data Gabungan golang WebSocket dan JSON: merealisasikan penghantaran dan penghuraian data Dec 17, 2023 pm 03:06 PM

Gabungan golangWebSocket dan JSON: merealisasikan penghantaran dan penghuraian data Dalam pembangunan Web moden, penghantaran data masa nyata menjadi semakin penting. WebSocket ialah protokol yang digunakan untuk mencapai komunikasi dua hala Tidak seperti model respons permintaan HTTP tradisional, WebSocket membenarkan pelayan untuk menolak data secara aktif kepada klien. JSON (JavaScriptObjectNotation) ialah format ringan untuk pertukaran data yang ringkas dan mudah dibaca.

Bagaimana untuk mengecualikan medan daripada JSON menggunakan anotasi @Expose dalam Java? Bagaimana untuk mengecualikan medan daripada JSON menggunakan anotasi @Expose dalam Java? Sep 16, 2023 pm 09:49 PM

Anotasi Gson@Expose boleh digunakan untuk menandakan sama ada medan terdedah (terkandung atau tidak) untuk bersiri atau penyahsirilan. Anotasi @Expose boleh mengambil dua parameter, setiap parameter ialah nilai boolean dan boleh mengambil nilai benar atau salah. Untuk GSON bertindak balas terhadap anotasi @Expose, kita perlu mencipta tika Gson menggunakan kelas GsonBuilder dan perlu memanggil kaedah excludeFieldsWithoutExposeAnnotation(), yang mengkonfigurasi Gson untuk mengecualikan semua medan tanpa anotasi Expose daripada bersiri atau penyahserialisasian. Sintaks publicGsonBuildereexclud

Apakah perbezaan antara MySQL5.7 dan MySQL8.0? Apakah perbezaan antara MySQL5.7 dan MySQL8.0? Feb 19, 2024 am 11:21 AM

MySQL5.7 dan MySQL8.0 ialah dua versi pangkalan data MySQL yang berbeza Terdapat beberapa perbezaan utama antara mereka: Peningkatan prestasi: MySQL8.0 mempunyai beberapa peningkatan prestasi berbanding MySQL5.7. Ini termasuk pengoptimum pertanyaan yang lebih baik, penjanaan pelan pelaksanaan pertanyaan yang lebih cekap, algoritma pengindeksan yang lebih baik dan pertanyaan selari, dsb. Penambahbaikan ini boleh meningkatkan prestasi pertanyaan dan prestasi keseluruhan sistem. Sokongan JSON: MySQL 8.0 memperkenalkan sokongan asli untuk jenis data JSON, termasuk penyimpanan, pertanyaan dan pengindeksan data JSON. Ini menjadikan pemprosesan dan memanipulasi data JSON dalam MySQL lebih mudah dan cekap. Ciri transaksi: MySQL8.0 memperkenalkan beberapa ciri transaksi baharu, seperti atomic

Petua pengoptimuman prestasi untuk menukar tatasusunan PHP kepada JSON Petua pengoptimuman prestasi untuk menukar tatasusunan PHP kepada JSON May 04, 2024 pm 06:15 PM

Kaedah pengoptimuman prestasi untuk menukar tatasusunan PHP kepada JSON termasuk: menggunakan sambungan JSON dan fungsi json_encode() menambah pilihan JSON_UNESCAPED_UNICODE untuk mengelakkan aksara melarikan diri menggunakan penimbal untuk meningkatkan prestasi pengekodan JSON; Pustaka pengekodan JSON.

Cara mengendalikan format data XML dan JSON dalam pembangunan C# Cara mengendalikan format data XML dan JSON dalam pembangunan C# Oct 09, 2023 pm 06:15 PM

Cara mengendalikan format data XML dan JSON dalam pembangunan C# memerlukan contoh kod khusus Dalam pembangunan perisian moden, XML dan JSON ialah dua format data yang digunakan secara meluas. XML (Extensible Markup Language) ialah bahasa penanda yang digunakan untuk menyimpan dan menghantar data, manakala JSON (JavaScript Object Notation) ialah format pertukaran data yang ringan. Dalam pembangunan C#, kami selalunya perlu memproses dan mengendalikan data XML dan JSON Artikel ini akan memfokuskan pada cara menggunakan C# untuk memproses kedua-dua format data ini dan melampirkan

Gunakan fungsi json.MarshalIndent dalam golang untuk menukar struktur kepada rentetan JSON yang diformatkan Gunakan fungsi json.MarshalIndent dalam golang untuk menukar struktur kepada rentetan JSON yang diformatkan Nov 18, 2023 pm 01:59 PM

Gunakan fungsi json.MarshalIndent dalam golang untuk menukar struktur menjadi rentetan JSON yang diformatkan Apabila menulis program dalam Golang, kita selalunya perlu menukar struktur menjadi rentetan JSON Dalam proses ini, fungsi json.MarshalIndent boleh membantu kita output berformat. Di bawah ini kami akan menerangkan secara terperinci cara menggunakan fungsi ini dan memberikan contoh kod khusus. Mula-mula, mari buat struktur yang mengandungi beberapa data. Berikut adalah petunjuk

Tutorial penggunaan Panda: Permulaan pantas untuk membaca fail JSON Tutorial penggunaan Panda: Permulaan pantas untuk membaca fail JSON Jan 13, 2024 am 10:15 AM

Permulaan Pantas: Kaedah Pandas membaca fail JSON, contoh kod khusus diperlukan Pengenalan: Dalam bidang analisis data dan sains data, Pandas ialah salah satu perpustakaan Python yang penting. Ia menyediakan fungsi yang kaya dan struktur data yang fleksibel, serta boleh memproses dan menganalisis pelbagai data dengan mudah. Dalam aplikasi praktikal, kita sering menghadapi situasi di mana kita perlu membaca fail JSON. Artikel ini akan memperkenalkan cara menggunakan Panda untuk membaca fail JSON dan melampirkan contoh kod tertentu. 1. Pemasangan Panda

Bagaimanakah anotasi dalam perpustakaan Jackson mengawal pensirilan dan penyahsirilan JSON? Bagaimanakah anotasi dalam perpustakaan Jackson mengawal pensirilan dan penyahsirilan JSON? May 06, 2024 pm 10:09 PM

Anotasi dalam perpustakaan Jackson mengawal pensirilan dan penyahserilangan JSON: Pensirilan: @JsonIgnore: Abaikan harta @JsonProperty: Tentukan nama @JsonGetter: Gunakan kaedah get @JsonSetter: Gunakan kaedah yang ditetapkan Deserialization: @JsonIgnoreProperties: Abaikan harta @ JsonProperty: Nyatakan nama @JsonCreator: Gunakan pembina @JsonDeserialize: Logik tersuai

See all articles