天天看點

使用 SpiderMonkey 使 C++應用支援 JavaScript 腳本引擎

這個教程的目的是示範如何使你的 C++ 應用能夠解釋執行 JavaScript 腳本。

SpiderMonkey, 是 Mozilla 項目的一部分, 是一個執行JavaScript腳本的引擎. 它用 C 實作。還有一個叫做 Rhino的Java版本。

也可以用 SpiderMonkey 在 Macintosh 和 Unix平台上. 讀 ReadMe.html 來學習在其他平台如何編譯。

JavaScript 運作時環境是調用 JS_NewRuntime 來初始化. 它配置設定運作時環境的所需記憶體。 你要指定所配置設定的位元組數,超過這個大小碎片收集器将運作。

上下文指定腳本棧的大小, 私有記憶體的位元組數被配置設定給指定腳本的執行棧. 每個腳本關聯于自己所擁有的上下文。

但上下文被一個腳本或線程使用時,其他腳本或線程不能使用。可當腳本或線程結束,這個上下文就可以被重用于下一個腳本或線程。

用 JS_NewContext 方法建立新的上下文。一個上下文和一個運作時環境關聯,你必須指定棧的大小。

在腳本執行前,你必須初始化 general JavaScript 函數和建立用于大多數腳本的 object 類.

全局對象( global object) 用 JSClass 結構來描述. 初始化這個結構如下:

現在你可以建立 global object  且初始化它。

執行腳本的一種途徑是用 JS_EvaluateScript 方法.

當這個腳本運作沒有錯誤, 今天的日期被儲存在 rval 中。rval 儲存函數最後的執行結果。JS_EvaluateScript的傳回值,運作成功是 JS_TRUE,發生錯誤是 JS_FALSE 。

從 rval 取回字元串的值如下所示。 這裡就不示範每個細節. 當你需要的時候檢視相關 API 的資訊。

在應用程式結束前, 必須清理腳本引擎.

在例子中使用的類如下:

建立一個新的 C++ 類,可以源于将在其中使用JavaScript的類,或者建立一個新類有一個那個類類型的成員。

在 JavaScript 中用結構 JSClass 來定義類. 建立一個這個類型的靜态(static)成員. 聲明為 public 成員, 因為這個結構要被其他類使用。它可以被用于其他類來确定對象類型. (參考 JS_InstanceOf API)

JSClass 結構包含 JavaScript 類的名字, 一些标志和 用于引擎回調的函數名. 例如一個回調用于當引擎需要從你的類中擷取一個屬性時。

在C++檔案的實作中定義 JSClass 結構,如下所示.

所用的回調是 JSCustomer::JSGetProperty, JSCustomer::JSSetProperty 和 JSCustomer::JSDestructor. JSGetProperty 當引擎擷取屬性時被回調, JSSetProperty 當引擎設定屬性時被回調,JSDestructor 當JavaScript 對象被銷毀時回調。

标志 JSCLASS_HAS_PRIVATE 用于訓示引擎開辟記憶體來綁定資料到 JavaScript 對象. 你可以用 this 存儲一個指向你的類的指針.

回調是C++類的靜态成員函數.

建立另一個叫 JSInit 的靜态方法 ,見下例. 這個方法将被應用程式調用,用來建立 JavaScript 運作時環境.

實作代碼如下

靜态方法 JSConstructor 當你的對象被腳本執行個體化的時候被調用. 這個方法非常友善用于綁定你的資料到對象,通過調用 JS_SetPrivate API.

這個構造器方法可以有多個參數, 能用于初始化你的類. 現在你已經在堆上建立了一個指針, 你也需要一種途徑銷毀這個指針. 這可以通過靜态方法 JS_Destructor 來完成.

增加一個類型為 JSPropertySpec 的靜态數組成員 . 這個數組将包含屬性資訊. 再建立一個屬性ID号的枚舉(enum).

在實作檔案中初始化這個數組,代碼如下

數組的最後一個元素必須是空(NULL). 每個元素包含另一個有 3 個元素的數組. 第一個元素是名字,将在 JavaScript 腳本中使用。第二個元素是屬性的唯一ID号, 将被傳遞到回調函數中。第三個元素是一個标志,JSPROP_ENUMERATE 表示腳本中當枚舉Customer對象的這個屬性時是可見的,就是可以用在腳本中的for 或 in 語句中. 你可以指定 JSPROP_READONLY 屬性來說明這個屬性是不可以修改的.

現在你能實作擷取(getting)和設定(setting)屬性的回調函數.

記得在屬性回調中傳回 JS_TRUE . 當你傳回 JS_FALSE 将表示在你的對象中沒有發現這個屬性.

建立類型為 JSFunctionSpec 的靜态成員數組.

數組的最後一個元素必須是空(NULL). 每個元素包含另一個有 5 個元素的數組. 第一個元素是腳本中使用的函數名. 第二個元素是全局或靜态成員函數名. 第三個元素是這個函數的參數個數. 最後兩個元素忽略.

在類中建立一個靜态方法

當函數成功就傳回 JS_TRUE . 否則傳回 JS_FALSE. 你的JavaScript方法實際傳回值被放到了 rval 參數中.

實作這個方法的例子

下面的腳本使用上面建立的對象

不要忘記當建立上下文的時候初始化 JavaScript 對象: