用函數模板,寫一個簡單高效的 JSON 查詢器的方法介紹_javascript技巧
JSON可謂是JavaScript的亮點,它能用優雅簡練的程式碼實作Object和Array的初始化。同樣是基於文字的資料定義,它比符號分隔更有語義,比XML更簡潔。因此在越來越多的JS開發中,使用它作為資料的傳輸和儲存。
JS陣列內建了不少有用的方法,方便我們對資料的查詢和篩選。例如我們有一堆資料:
var heros = [
var heros = [
// 名============攻=====防=======力量====敏捷=====智力====
{ name:'冰室女巫', DP:38, AP:1.3, Str:16, Agi:16, Int:21},
{name:'沉默術士', DP:39, AP:1.1, StrStr: 17, Agi:16, Int:21},
{name:'娜迦海妖', DP:51, AP:6.0, Str:21, Agi:21, Int:18},
:'賞金獵人', 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},
'煉金術士', DP:49, AP:0.6, Str:25, Agi:11, Int:25}
//...
...
];
程式碼如下:
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>顯然,如果能將另一種語言,翻譯成js程式碼,那麼就可直接交給宿主來執行了! <P> <P>例如上面select中的字符,我們簡單的將"@"替換成"e.", "AND"替換成"&&",於是就成了一個合法的js表達式,完全可以交給eval來執行。 <P>所以我們要做的,就是將原始語句翻譯成js語句來執行。並且為了提高效率,將翻譯好的js表達式內聯到一個上下文環境,產生一個可執行的函數體,而不是每次遍歷中都依靠回調來判斷。 <STRONG> <br>於是,函數模版就要派上用場了。 <br> <BR>函數模版簡介<div class="codetitle"><span><a style="CURSOR: pointer" data="84492" class="copybut" id="copybut84492" onclick="doCopy('code84492')">在C 裡面,有宏和類模版這麼東西,可以讓一些計算在編譯階段就完成了,大幅提升了運行時代碼的性能。雖然腳本沒有嚴格意義上的編譯,但在第一次執行的時候會解析並充分的最佳化,這是目前主流瀏覽器相互競爭點。所以,我們要將重複eval的程式碼,鑲嵌到事先提供的樣板函數裡:一個準備就緒,就差表達式計算的函數:<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> }<BR> return count;<BR> }<BR><BR><BR>上面就是一個範本函數,遍歷參數arr []並統計符合$express的數量。除了if(...)內的表達式外,其他都已經準備就緒了。字元$express也可以換成其他標識,只要不和函數內其他字元衝突即可。 <BR>當我們需要實例化時,首先透過tmplCount.toString()將函數轉成字串格式,然後將其中的$express替換成我們想要的表達式,最後eval這串字符,得到一個Function類型的變量,一個模板函數的實例就產生了! <P>我們簡單的示範下:<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> <BR> /**<BR> * 函數: createInstance<BR> * 參數: exp<BR> * 回傳一個Function,模版tmplCount的例<BR> */<BR> function createInstance(exp)<BR> {<BR> .replace ('$express', exp);<BR><BR> // 防止匿名函數直接eval封包錯誤<br> var fn = eval('0,' code);<br> <BR> // 回傳範本實例 return fn;<P> }<BR> <BR> // 測試參數<P> var student = [<BR> {name: 'Jane' {name: 'Adam', age: 18}<BR> ];<BR> <BR> // demo1<BR> var f1 = createInstance('e.age<16');<BR> alert(f1(student)); 11個 <P> // demo2<BR> var f2 = createInstance('e.name!="Jack" && e.age>=14');<BR> alert(f2(student)); ><P>注意createInstance()的參數中,有個叫e的對象,它是在tmplCount模版中定義的,指代遍歷時的具體元素。傳回的f1,f2就是tmplCount模板的兩個實例。在最終調用的f1,f2函數中,已經內嵌了我們的表達式語句,就像我們事先寫了兩個同樣函數的函數一樣,所以在遍歷的時候直接運行表達式,而不用回調什麼的,效率大幅提升。 <BR> <BR><BR> <BR>其實說穿了,tmplCount的存在只是為了提供這個函數的字串而已,本身從來就不會被呼叫。事實上用字串的形式定義也一樣,只不過用函數書寫比較直觀,方便測試。 <P>值得注意的是,如果腳本後期需要壓縮優化,那麼tmplCount模板絕對不能參與,否則對應的"e."和"$express"都有可能改變。 <img src="/static/imghw/default1.png" data-src="http://files.jb51.net/file_images/article/201304/201304171146157.png" class="lazy" alt=""> <P>JSON基本查詢功能<P> 函數範本的用處和實作介紹完了,再來回頭看之前的JSON查詢語言。我們只要將類似sql的語句,翻譯成js表達式,並且產生一個函數模板實例。對於相同的語句,我們可以進行緩存,避免每次都翻譯。 <P> <STRONG>首先我們實作查詢器的範本:<P><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的元素集合< var __tmpl = function(_list) {<BR> var _ret = [];<BR> var _i = -1;<BR> <BR> for(var _k in _list) { var _e = _list[_k]< proto[_k]) {<P> if($C)<BR> _ret[ _i] = _e;<br> return _ret;<br> <BR> }.toString();<BR><BR><BR><BR>然後開始寫Object的select方法:<P><BR><BR><STRONG><BR><div class="codetitle"><> 🎜><span><a style="CURSOR: pointer" data="74878" class="copybut" id="copybut74878" onclick="doCopy('code74878')"> 程式碼如下:<U> // // select方法實作 //<div class="codebody" id="code74878"> // select方法實作<BR> //<BR> __proto.select = function(exp) {<BR> if(!exp)<BR> return [];<br> <br> var fn = __cache[exp];<BR> <BR> try { if(!fn) {<P> //解釋表達式 code = __tmpl.replace('$C', code); 到模版<P> <BR> fn = __cache[exp] = __compile(code); //實例化函數<BR> <BR> return fn(this); catch(e) { return [];<P> 其中__cache表實作了查詢語句的快取。對於重複的查詢,效能可以極大的提升。 <BR><P><BR><BR>複製碼<BR><BR><BR> 代碼如下:<BR><BR> function 🎜><BR><div class="codetitle"> function 🎜><span><a style="CURSOR: pointer" data="94768" class="copybut" id="copybut94768" onclick="doCopy('code94768')"> 0,' arguments[0]);<U> } __compile之所以單獨寫在一個空函數裡,就是為了eval的時候有個盡可能乾淨的上下文環境。 <div class="codebody" id="code94768">__interpret是整個系統的重中之重,負責將查詢語句翻譯成js語句。它的實現見智見仁,但盡可能簡單,不要過度分析語法。 <BR> <BR>具體程式碼檢視:<BR>jsonselect.rar<BR>出於演示,目前只實現部分基本功能。以後還可以再加上 LIKE,BETWEEN,ORDER BY 等等常用的功能。 <BR> <P>Demo<P><A href="http://xiazai.jb51.net/201304/yuanma/jsonselect.rar" target=_blank><BR>複製程式碼<P><STRONG><BR> 程式碼如下:<div class="codebody" id="code75283"><BR>var heros = [<BR> // 名============攻=====防=======力量====敏捷== ===智力====<BR> {name:'冰室女巫', DP:38, AP:1.3, Str:16, Agi:16, Int:21},<BR> ', DP:39, AP:1.1, Str:17, Agi:16, Int:21},<BR> {name:'娜迦海妖', DP:51, AP:6.0, Str:21, Agigi: 21, Int:18},<BR> {name:'賞金獵人', DP:39, AP:4.0, Str:17, Agi:21, Int:16},< ', 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><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><BR>敏捷都超過20的<BR> // 結果:娜迦海妖 var match = heros.select('@Str>20 AND @Agi>20');<P> <BR> // 查詢:「士」結尾的<BR> // 結果:沉默術士,劇毒術士,煉金術士 var match = heros.select('right(@name,1)="士" ');<P> <BR> // 查詢:生命值超過500的<BR> // 結果:煉金術士<BR> var match = heros.select('100 @Str*19 > 500');<🜎 ><BR></script>

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

golangWebSocket與JSON的結合:實現資料傳輸和解析在現代的Web開發中,即時資料傳輸變得越來越重要。 WebSocket是一種用於實現雙向通訊的協議,與傳統的HTTP請求-回應模型不同,WebSocket允許伺服器向客戶端主動推送資料。而JSON(JavaScriptObjectNotation)是一種用於資料交換的輕量級格式,它簡潔易讀

Gson@Expose註解可用於標記欄位是否公開(包含或不包含)以進行序列化或反序列化。 @Expose註解可以採用兩個參數,每個參數都是一個布林值,可以採用值true或false。為了讓GSON對@Expose註解做出反應,我們必須使用GsonBuilder類別建立一個Gson實例,並且需要呼叫excludeFieldsWithoutExposeAnnotation()方法,它將Gson配置為排除所有沒有Expose註解的欄位進行序列化或反序列化。語法publicGsonBuilderexclud

MySQL5.7和MySQL8.0是兩個不同的MySQL資料庫版本,它們之間有以下一些主要差異:效能改進:MySQL8.0相對於MySQL5.7有一些效能改進。其中包括更好的查詢優化器、更有效率的查詢執行計劃產生、更好的索引演算法和平行查詢等。這些改進可以提高查詢效能和整體系統效能。 JSON支援:MySQL8.0引入了對JSON資料類型的原生支持,包括JSON資料的儲存、查詢和索引。這使得在MySQL中處理和操作JSON資料變得更加方便和有效率。事務特性:MySQL8.0引進了一些新的事務特性,如原子

PHP數組轉JSON的效能最佳化方法包括:使用JSON擴充和json_encode()函數;新增JSON_UNESCAPED_UNICODE選項以避免字元轉義;使用緩衝區提高循環編碼效能;快取JSON編碼結果;考慮使用第三方JSON編碼庫。

使用golang中的json.MarshalIndent函數將結構體轉換為格式化的JSON字串在使用Golang編寫程式時,我們經常需要將結構體轉換為JSON字串,在這個過程中,json.MarshalIndent函數可以幫助我們實現格式化的輸出。下面我們將詳細介紹如何使用這個函數,並提供具體的程式碼範例。首先,讓我們建立一個包含一些資料的結構體。以下是示

C#開發中如何處理XML和JSON資料格式,需要具體程式碼範例在現代軟體開發中,XML和JSON是廣泛應用的兩種資料格式。 XML(可擴展標記語言)是一種用於儲存和傳輸資料的標記語言,而JSON(JavaScript物件表示)是一種輕量級的資料交換格式。在C#開發中,我們經常需要處理和操作XML和JSON數據,本文將重點放在如何使用C#處理這兩種數據格式,並附上

快速入門:Pandas讀取JSON檔案的方法,需要具體程式碼範例引言:在資料分析和資料科學領域,Pandas是一個重要的Python庫之一。它提供了豐富的功能和靈活的資料結構,能夠方便地對各種資料進行處理和分析。在實際應用中,我們經常會遇到需要讀取JSON檔案的情況。本文將介紹如何使用Pandas來讀取JSON文件,並附上特定的程式碼範例。一、Pandas的安裝

Jackson庫中的註解可控制JSON序列化和反序列化:序列化:@JsonIgnore:忽略屬性@JsonProperty:指定名稱@JsonGetter:使用獲取方法@JsonSetter:使用設定方法反序列化:@JsonIgnoreProperties:忽略屬性@ JsonProperty:指定名稱@JsonCreator:使用建構子@JsonDeserialize:自訂邏輯
