1. 程式人生 > >自制JSON解析庫C++(一)--對JavaScript物件的理解

自制JSON解析庫C++(一)--對JavaScript物件的理解

JSON只有兩種結構:鍵值對和陣列;它們之間可以相互巢狀,形成樹形結構,葉子節點有字串、數字、false、true、null。

 

 

在這之前,首先談談對JavaScript核心思想的理解:

 

在JS的世界裡,沒有類,只有物件,物件怎麼來,通過動態新增屬性和方法造出來。

 

沒有類很麻煩,假如多個地方要用到類似的物件,就得造多次。

 

JS有辦法,一是通過方法造,造好了返回,方法像是工廠,也像C++的建構函式;二是通過原型造,也是設計模式中的原型模式,原型既是物件,也是物件的模具。

 

JS裡的方法和C++不一樣,方法也是物件,更像C++的可呼叫物件。語法上所有物件都可以呼叫,方法也可以為自己新增屬性,方法也可以賦值給屬性,本質上物件、方法、屬性沒有區別。

 

JS裡的new相當於建立空物件,以該物件繫結為函式的this,然後呼叫函式的過程。

 

雖然說在JS裡一切皆物件,整個程式也是一個全域性物件(全域性函式),但是有幾個比較特殊的:字串、數值、true、false、null、undefined、NaN,這些都是不可變物件。其中字串、數值、true/false有包裝物件String、Number、Boolean。其實在JS中當做物件使用時會進行包裝處理(null、undefined除外),訪問字串、數值、true/false的屬性時,其實是訪問了String、Number、Boolean臨時物件的屬性,即使對其屬性賦值也不會影響它的狀態。

 

 

JSON是JavaScript物件的字串表示,JavaScript有內建的方法eval可以解析(或者JSON.parse、JSON.stringify),所以JSON和JavaScript物件是有對應關係的。

 

既然這樣,如果要寫一個C++的JSON解析庫,那麼C++端也應該有對JavaScript物件進行抽象的實體類,表示JSON解析的結果,也表示所有的JavaScript物件,暫且命名為js::Object。

 

解析的介面也不標新立異了,和JavaScript保持一致,定為js::JSON::parse、js::JSON::stringify。不用eval,因為eval不只針對JSON,而是可以解析任何JavaScript語句。

 

對於上面的特殊物件字串、數值、true/false、null、undefined、NaN,C++端需要單獨考慮,可以進行顯式解包裝,在js::Object提供toString、toBoolean之類的方法。但是從另一方面考慮,js::Object是對JavaScript所有實體的抽象,而toString之類的方法只是提供向C++型別轉換的方便,是不是將toString之類的方法放在一個工具類裡會更好呢?工具類暫且命名為JsObjectToCppType。

 

上面的特殊物件字串、數值、true/false、null、undefined、NaN,都是不可變物件,可以有改變其屬性的語句,雖然不會有錯誤和異常,但不會產生效果,這點在C++端如何模擬?容易想到的是繼承,特殊物件繼承js::Object,然後重寫一些實現,但是這會帶來一些問題。因為多型只能通過引用和指標實現,將解析的結果以引用的方式返回是不好的,返回堆物件指標又會有記憶體管理的問題,對這種輕量級的物件使用智慧指標感覺不太好,也會增加複雜度。考慮下JavaScript的多型,其實是利用了動態語言可以動態改變物件的屬性和方法的特性,那麼C++也可以在js::Object中使用動態方法,首先將js::Object的建構函式設為私有,通過工廠函式設定動態方法構造不同的js::Object。

 

物件屬性的訪問,JavaScript的屬性訪問方式有兩種,object.property和object[property],前一種“.”運算子在C++中不能被過載且C++不支援動態屬性,所以解析庫只模擬後一種。