JavaScript在瀏覽器中的應用幾乎是盡人皆知的。實際上,JavaScript技術也可以使用在非瀏覽器應用程式當中,從而讓應用程式具有自動的指令碼功能。本文介紹了一種功能非常強大的JavaScript引擎SpiderMonkey。這個引擎是Mozilla 瀏覽器的 JavaScript引擎。該引擎介面定義清晰,模組化好。本文簡要介紹了 SpiderMonkey的基本結構,並講解了如何在自己的應用程式中使用該引擎,最後給出了一個範例程式。該程式能夠解釋執行JavaScript指令碼完成簡單的指令碼功能。
JavaScript是由Netscape開發的對象指令碼語言,其特點是開發簡單、功能靈活,目前已廣泛應用於WEB頁面及伺服器應用程式中。HTML本身是靜態、不允許使用者幹預,但用JavaScript編寫的指令碼程式就可以在使用者的瀏覽器端運行,可以同使用者進行互動,從而實現動態網頁面。可以將JavaScript與嵌入WEB的大多數對象的事件(如滑鼠點擊、移動等)相關聯,然後用自己的方式處理這些事件。JavaScript提供了豐富的內建函數及命令,能在瀏覽器中顯示HTML、數值計算、多媒體播放、超級連結以及簡單的互動視窗等,還可以使在瀏覽器中啟動並執行小Java應用程式的性質改變從而很容易地改變控制項或其它對象的行為而不必深入研究其本身的結構。
JavaScript雖然是為Internet而開發的,但它的應用卻不僅僅局限於Internet,事實上由於其物件導向的特性使得其適用範圍非常廣泛,只要我們的應用程式具有良好的對象機制,我們就可以借用JavaScript,從而實現很好的互動功能。
SpiderMonkey是由C語言操作的JavaScript引擎,它支援JS1.4和ECMAScript-262規範。該引擎分析、編譯和執行指令碼,根據JS資料類型和對象的需要進行記憶體配置及釋放操作。利用該引擎可以讓你的應用程式具有解釋JavaScript指令碼的能力,目前已有若干個項目都採用了SpiderMonkey引擎,像K-3D、WebCrossing、WebMerger等。K-3D是用C++實現的3D建模與模擬系統,該系統內嵌SpiderMonkey引擎來提供自訂指令碼(使用者建立指令碼產生像齒輪一樣具有重複特性的複雜形體),也可用來驅動互動教學系統(使用者可以使用一段JS指令碼程式記錄其互動過程,如移動滑鼠、選擇菜單、點擊滑鼠等)。WebCrossing利用SpiderMonkey實現了伺服器端的指令碼環境,提供了完全的Web-server指令碼環境,伺服器端的實現允許你在內建的、物件導向的資料庫中建立永久對象,這樣即可根據自己的需要擴充伺服器環境。
下面簡要介紹在自己的應用程式中如何使用SpiderMonkey,最後給出一個簡單的例子程式。
如何使用引擎
JS引擎一般作為共用庫使用,應用程式調用引擎提供的API函數。引擎API函數大致分為以下幾種:資料類型操作、RunTime控制、類與對象的建立和維護、函數與指令碼執行、字串操作、錯誤處理、安全控制、Debug支援。一般情況下,在你的應用程式中只需使用某幾類函數。例如,在進行JS調用之前你必須調用JS_NewRuntime函數來建立並初始化JS引擎。有些類型的函數,象安全控制類,提供可選擇的特徵。
從概念上講,JS引擎是你系統上的一個共用資源。通過將引擎API調用嵌入到應用程式中(包含jsapi.h檔案),你可以請求JS引擎進行操作。接下來,引擎處理你的請求,並將結果或狀態資訊返回給你的應用程式。
例如,假定你在使用JS引擎自動化應用程式,指令碼應用程式鑒別使用者並設定許可權。首先,應用程式建立JS對象,該對象描述使用者資訊,包括姓名、ID、許可權和可用的函數列表。在這種情況下,應用程式首先調用JS_NewObject建立對象。當JS引擎建立對象後,返回一個指標給應用程式。應用程式再調用JS引擎執行指令碼。在建立使用者物件後,應用程式即刻傳遞指令碼給JS_EvaluateScript以便編譯和運行。指令碼或許取得並效驗使用者資訊,然後建立使用者存取的權利。
JS引擎收到初始化請求後,給JS RunTime分配記憶體,應用程式使用的變數、對象和上下文(上下文)都儲存在RunTime中。一個上下文是指令碼的執行狀態(JS引擎使用的)。每個同時存在的指令碼或線程都必須有自己的上下文。單個的JS RunTime可以包含多個上下文、對象和變數。幾乎所有的JS引擎調用都需要一個上下文變數,應用程式在建立RunTime後,首先應調用至少一次JS_NewContext來建立一個上下文。內容相關的實際數量依賴於程式中同時使用的指令碼數。程式中每個同時存在的指令碼都需要一個上下文。另一方面,如果某個時刻只有一個指令碼編譯和運行,那麼你只需一個上下文給每個指令碼重複使用即可。
在建立上下文後,要調用JS_InitStandardClasses初始化引擎中的內建JS對象,包括Array、Boolean、Date、Math、Number和String。即使在建立對象時傳遞一個特定的上下文給JS引擎,這個對象在RunTime中也是獨立於上下文。任意指令碼能與任意上下文建立聯絡以便存取任意對象。指令碼、上下文相互之間完全獨立,即使它們存取同樣的對象。在給定的RunTime中,應用程式能用未指定的上下文存取任意對象。你可以建立獨立的RunTime,一個用於共用上下文和對象,其餘的用於私人上下文和對象。但注意,某個時刻只有一個線程能存取特定的上下文。要讓應用程式能識別JS,嵌入適當的引擎調用到你的程式中。大致有以下幾個方面:
- 程式中包含jsapi.h。
- 程式中提供結構和變數聲明。例如,如果你計劃傳遞一個指令碼給JS引擎,提供一個指令碼字串變數。用jsapi.h中定義的JS資料類型來聲明變數。
- 使用JavaScript的指令碼應用對象。通常這些對象與C程式中的結構和方法相對應。
- 將JS引擎API函數調用和變數引用插入到程式中,包括初始化內建JS對象、建立並配置使用者自訂對象。
- 大多數JS引擎調用返回一個值。如果該值是NULL,一般表示錯誤發生。如果非NULL,表示成功,傳回值一般是指標,程式需要使用或留到將來使用。應用程式應檢查JS引擎調用的傳回值。
要讓應用程式能解釋JavaScript,你必須遵循某些JS API嵌入習慣。下面的例子簡要說明需要嵌入到你的應用程式中去的一些API調用函數。大部分情況下,這些函數的插入順序是很重要的。例如,在調用其他JS API之前必須初始化JS RunTime,同樣在終止程式之前必須釋放JS RunTime。
#include <stdio.h>#include <stdlib.h>#include <string.h>/* 包含JS引擎的API標頭檔 */#include "jsapi.h"...//主程式聲明全域JS變數,包括RunTime、一個Context和一個全域對象,然後初始化JS RunTime、建立一個Context。int main(int argc, char **argv){ int c, i; /*聲明全域JS變數,包括全域和自訂對象*/ JSVersion version; JSRuntime *rt; JSContext *cx; JSObject *glob, *it; JSBool builtins; /* 初始化JS RunTime,返回結果給rt */ rt = JS_NewRuntime(8L * 1024L * 1024L); /* 如果rt為空白,程式終止 */ if (!rt) return 1; /* 建立一個Context,並將其與JS RunTime關聯起來 */ cx = JS_NewContext(rt, 8192); /* 如果cx為空白,程式終止 */ if (cx == NULL) return 1; /* 建立全域對象 */ glob = JS_NewObject(cx, clasp, NULL, NULL); /* 執行個體化內建對象和全域對象*/ builtins = JS_InitStandardClasses(cx, glob); . . . return 0;} |
如上面這個例子所示,調用JS引擎的應用程式必須首先建立JS RunTime,而且在終止程式之前要釋放這個RunTime。在執行個體化RunTime後,即可建立自己的JS物件模型。物件模型決定了JS對象之間的關係,JS對象本質上是一種階層。預設情況下,所有的JS對象都與全域對象相關聯,它們都是全域對象的後代。當初始化標準的JS類時,你自動地得到一個全域對象:
builtins = JS_InitStandardClasses(cx, glob);
這個全域對象建立了一些基本的、被其它對象所繼承的性質和方法。當你建立自訂對象時,它們自動使用全域對象所定義的性質和方法。你可以在自訂對象上重新定義這些性質和方法,從而重載這些預設的性質和方法。當然,你也可以接受這些預設的分配。你可以在內建JS對象或其它自訂對象的基礎上建立自己的對象。無論哪種情況,你所建立的對象都繼承了層次鏈中父物件、一直上溯到全域對象的全部性質和方法。
管理RunTime
JS RunTime是記憶體空間,JS引擎利用它來管理上下文、對象和與JS函數及指令碼相關的變數。在執行JS函數或指令碼之前,首先要調用JS_NewRunTime來初始化一個RunTime。JS_NewRunTime函數攜帶一個unsigned整型參數,這個參數指定了在片段收集之前分配給RunTime記憶體的最大位元組數。例如:
rt = JS_NewRuntime(8L * 1024L * 1024L);
如上所示,JS_NewRuntime返回一個指向RunTime的指標。非NULL表示建立成功。
正常情況下,一個程式只需一個RunTime。當然,根據需要建立多個RunTime並將它們儲存在不同指標上也是可以的。
JS_DestroyRuntime(rt);
如果你建立了多個RunTime,務必在應用程式終止前將每個都銷毀。
管理上下文(Contexts)
幾乎所有的JS API調用都要求你傳遞一個上下文參數。在JavaScript引擎中一個上下文代表一個指令碼,引擎傳遞上下文資訊給運行指令碼的線程。每個同時啟動並執行指令碼必須指派一個唯一的上下文。當一個指令碼運行完後,它的上下文也不再有用,因此這個上下文可以重新指派給一個新的指令碼,或將其釋放。
調用函數JS_NewContext為某個指令碼建立一個新的上下文。這個函數需要兩個參數:一個與該上下文相關的RunTime指標,分配給該內容相關的棧空間位元組數。如果調用成功,函數返回一個指標,它指向這個建立立的上下文。例如:
JSContext *cx; . . .cx = JS_NewContext(rt, 8192); |
這個RunTime必須已經存在。你指派給內容相關的棧空間必須足夠大以便提供給使用該內容相關的指令碼所建立的變數和對象。注意,因為需要一些與分配和維護上下文相關的overhead,你必須做到:在應用程式中必鬚根據需要來確定建立內容相關的數量;要確保上下文在被應用程式所需要時存在,而不是反覆銷毀和需要時重新建立。
當某個上下文不再需要時,它應被銷毀、釋放記憶體資源給其它程式使用。根據應用程式中JS使用的範圍,可以在使用完後及時銷毀,或將其保留並反覆利用直到應用程式終止。無論哪種情況,當上下文不再需要時都要調用函數JS_DestroyContext來釋放它,這個函數攜帶一個指標參數,它指向要被釋放的上下文:
JS_DestroyContext(cx);
如果你的應用程式建立了多個RunTime,那麼,應用程式可能需要知道某個上下文是與哪個RunTime相關聯的。這種情況下,可以調用函數JS_GetRuntime,同時傳遞該上下文作為參數。JS_GetRuntime返回一個指標,它指向合適的RunTime(如果存在的話):
rt=JS_GetRuntime(cx);
當你建立一個上下文,你要給它指派棧空間用於存放變數和對象。在一個給定的上下文中,你也能夠存放大量的資料。但是,你必須將所需的棧空間儘可能地降到最小。調用JS_SetContextPrivate函數建立一個指標,它指向該上下文所需的私人資料,調用JS_GetContextPrivate函數得到這個指標以便你能存取這資料。你的應用程式負責建立和管理私人資料。
要建立私人資料並將其與上下文相關聯:首先,建立私人資料,即常規的C語言void* 變數;然後,調用JS_SetContextPrivate函數,並指定建立私人資料的上下文和指向該資料的指標。例如:
JS_SetContextPrivate(cx,pdata);
隨後要擷取這個資料指標,請調用JS_GetContextPrivate,並傳遞這個上下文作為參數。這個函數返回指向私人資料的指標:
pdata=JS_GetContextPrivate(cx);
<?xml encoding="US-ASCII"?><!ELEMENT order (header,item+,price)><!ELEMENT header (billing,shipping)><!ELEMENT billing (name,address,creditCard)><!ELEMENT shipping (name,address)><!ELEMENT name EMPTY> |
對象的處理
1.建立內建對象和全域JS對象
JavaScript引擎提供若干個內建對象,使得你的開發工作單位得以簡化。例如,內建數組(Array)對象使得在JS引擎中建立和運算元組結構很容易。類似地,日期(Date)對象提供了一個操作日期的統一機制。要瞭解內建對象支援的全部內容,請參閱JS_InitStandardClasses。 JS引擎一直使用函數和全域對象。通常,全域對象居留在幕後,為應用程式中建立和使用的其它JS對象及全域變數提供預設範圍。在建立自己的對象前,你必須初始化全域對象。函數對象使得對象具有和調用建構函式的功能。
一個簡單的API調用,JS_InitStandardClasses,初始化全域和函數對象、內建引擎對象,方便應用程式使用它們:
JSBool builtins; . . .builtins = JS_InitStandardClasses(cx, glob); |
JS_InitStandardClasses函數返回一個JS布爾值,表示初始化成功與否。
你也可以為應用程式指定另外一個不同的全域對象。例如,Navigator使用window作為其全域對象。要改變應用程式的全域對象,請調用JS_SetGlobalObject。要瞭解更多資訊,請參閱JS_SetGlobalObject。
2.建立並初始化自訂對象
除了使用引擎內建對象外,你還可以建立、初始化並使用自己的JS對象。特別是你在使用JS引擎用指令碼來自動化應用程式時更是如此。自訂的JS對象能提供直接的程式服務,或者作為你的程式服務的介面。
有兩種方法來建立JS引擎能使用的自訂對象:
- 寫一個JS指令碼,它建立一個對象、性質、方法、建構函式,然後將這個指令碼傳遞給JS引擎。
- 將代碼插入到你的應用程式中,它定義了對象的性質和方法,調用引擎來初始化一個新對象,然後通過額外的引擎調用設定對象的性質。這種方法的好處是,應用程式能包含操作對象的本地方法。
無論哪種情況,如果你建立一個對象,然後讓其存在於被其它指令碼使用的RunTime中,你可以調用JS_AddRef和JS_AddNamedRoot使該對象為根。使用這些函數,確保JS引擎能跟蹤這些對象並在片段收集時清除它們。
3.如何將自訂對象嵌入到應用程式中
將自訂對象插入到應用程式中是很有用的,比如,當對象持續需要時,或者你知道有多個指令碼需要使用一個對象。將自訂對象插入到應用程式中的步驟是:
- 建立一個JSPropertySpec資料類型,將對象的屬性資訊指派給它,包括屬性的GET和PUT方法名字。
- 建立一個JSFunctionSpec資料類型,將被你的對象所使用的方法資訊指派給它。
- 建立實際的C函數,它們在響應你的對象方法調用時被執行。
- 調用JS_NewObject和JS_ConstructObject函數,以便執行個體化該對象。
- 調用JS_DefineFunctions函數來建立對象的方法。
- 調用JS_DefineProperties函數來建立對象的屬性。
描述持續的、自訂的JS對象的代碼必須放在靠近程式執行的開始部分,在那些依耐於先前已存在對象的代碼之前。
4.給對象提供私人資料
象上下文一樣,你可以將大量的資料與對象進行關聯,而不是將這些資料直接存放在對象裡。調用JS_SetPrivate函數來建立指向對象私人資料的指標,調用JS_GetPrivate函數來擷取這個指標以便你能存取這些資料。你的應用程式負責建立和管理這些私人資料。
建立私人資料並將其與對象關聯的方法:
1)建立私人資料,作為C語言的void*變數。 2)調用JS_SetPrivate函數,指定對象和私人資料指標。
例如:
JS_SetContextPrivate(cx,obj,pdata);
隨後,要擷取這些資料,請調用JS_GetPrivate函數,將對象作為參數進行傳遞。這個函數返回指向對象私人資料的指標:
pdata=JS_GetContextPrivate(cx,obj);
資料處理
1.處理JS資料類型
JavaScript定義了自己的資料類型。有些資料類型直接對應於C語言中的副本。其它的,如JSObject、jsdouble和JSString,都是JavaScript專屬的。
通常,你可以在應用程式中像使用標準的C語言資料類型一樣聲明、使用JS資料類型,JS引擎對那些需要多於一個字儲存空間的JS資料類型的變數保持單獨的棧,例如:JSObject、jsdouble和JSString。引擎會周期性地檢查這些變數,看看它們是否仍在使用,如果沒有,引擎就片段收集它們,釋放儲存空間。
2.處理JS值
除了JS資料類型以外,JS引擎也使用JS值,稱其為jsvals。一個jsval本質上是一個指標,指向除了整型以外的JS資料類型。對於整型,一個jsval包含這個值自身。其它情況,指標被編碼成包含額外資訊。利用jsvals提高引擎的效率,允許API函數處理大量的潛在資料類型。引擎API包含一組宏,用於測試一個jsval的JS資料類型。他們是:
- JSVAL_IS_OBJECT
- JSVAL_IS_NUMBER
- JSVAL_IS_INT
- JSVAL_IS_DOUBLE
- JSVAL_IS_STRING
- JSVAL_IS_BOOLEAN
除了測試一個jsval的潛在資料類型外,也能測試它看是否是原始JS資料類型(JSVAL_IS_PRIMITIVE)。未經處理資料類型是undefined、null、boolean、numeric和string類型。
你也可測試jsval指向的值是否為NULL(JSVAL_IS_NULL)或void(JSVAL_IS_VOID)。
如果一個jsval指向一個JSObject、 jsdouble或 jsstr等JS資料類型,你可利用JSVAL_TO_OBJECT、 JSVAL_TO_DOUBLE、 JSVAL_TO_STRING將jsval轉為它的潛在類型。
3.處理JS字串
你在JavaScript中做的許多事情都會涉及到字串,JS引擎實現了一個稱為JSString的字串資料型別和一個指向JS字元數組的指標類型即jschar,用類處理Unicode編碼的字串。這個引擎也實現了一組通用的Unicode字串程式。最後,JS引擎也提供內建串的支援,兩個或多個獨立的字串在記憶體中能共用一個串。對於JSString類型的字串,這個引擎跟蹤並管理串資源。
一般說來,當你用JS引擎操縱字串時,你應該用JS API串處理函數來建立和複製字串。有字串管理程式用於建立NULL結尾的字串或者指定長度的字串。同時,也有程式用於計算字串長度、比較字串。
4.對Unicode和Interned字串的支援
像其他API調用一樣,具有Unicode能力的API字串函數的名字與標準的引擎API字串函數的名字是一一對應的。例如,如果一個標準函數名為JS_NewStringCopyN,對應的Unicode版函數就是JS_NewUCStringCopN。具有Unicode處理能力的API字串函數對於interned字串也是可行的。
為了節約空間,JS引擎為共用單個字串執行個體提供支援。這種共用的字串稱為"interned strings"。當你事Crowdsourced Security Testing道程式中會建立一個特定的、文本字串並且要多次使用它時,請利用interned字串。
引擎為interned字串提供了若干個調用:
- JS_InternString,用於建立或再次使用一個JSString。
- JS_InternUCString,用於建立或再次使用一個Unicode類型的JSString。
- JS_InternUCStringN,用於建立或再次使用固定長度的Unicode型JSString。
5.安全控制
對於JavaScript1.3,JS引擎增加了安全增強型API函數,用於編譯和運行傳遞給引擎的指令碼或函數。JS安全模型是基於Java安全模型的。這個模型提供了一個通用的安全介面,但是,具體的安全實現是由應用程式自己來完成的。
安全機制用在能夠支援JavaScript的應用程式中的一種通用情形是比較指令碼的真實性或者限制指令碼的互動性。例如,你可以比較一個應用程式中兩個或多個指令碼的程式碼程式庫,只允許來自同一個程式碼程式庫的指令碼能夠修改共用程式碼程式庫的指令碼屬性。
如果要實現安全JS,請按以下步驟:
1)在程式中聲明一個或者多個JSPrincipals類型的結構。
2)實現將給數組提供安全資訊的函數。這些函數包括:給你的應用程式提供一個principals數組,用一套給定的規則對JS對象的引用數進行加減操作的機制。
3)用你的安全資訊給JSPrincipals結構賦值,這個資訊可以包括通用代碼資訊。
4)在已耗用時間環境中,編譯與執行全部指令碼和函數。下面列出了這些API函數和它們的目的:
- JS_CompileScriptForPrincipals:編譯但不執行一段具有安全能力的指令碼。
- JS_CompileUCScriptForPrincipals:編譯但不執行一段具有安全能力、Unicode編碼的指令碼。
- JS_CompileFunctionForPrincipals:利用一個文本字串建立一個具有安全能力的JS函數。
- JS_CompileUCFunctionForPrincipals:利用一個Unicode編碼的文本字串建立一個具有安全資訊的JS函數。
- JS_EvaluateScriptForPrincipals :編譯並執行一段具有安全能力的指令碼。
- JS_EvaluateUCScriptForPrincipals:編譯並執行一段具有安全能力、用Unicode編碼的指令碼。
程式範例
以下是一個簡單的範例程式,它從檔案test.js中讀入一段指令碼,然後解釋執行並輸出結果。指令碼中可嵌入自訂對象People,People對象具有屬性name(表示該人的姓名)、address(表示該人的地址)及方法print(在螢幕上顯示該人的姓名、地址資訊)。
例如:下面是一段簡單的js指令碼,它首先利用print方法輸出該人的姓名和地址,然後將姓名和地址分別修改為John和Beijing,最後再次輸出其姓名和地址,看是否修改正確。
people.print();
people.name="John";
people.address="Beijing";
people.print();
下面是C來源程式代碼。
#include "js.h"enum tagMY_PEOPLE {MY_NAME,MY_ADDRESS};static JSBool GetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp);static JSBool SetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp);static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);typedef struct{ char name[16]; char addr[64];}PeopleInfo;static PeopleInfo m_ainfo={"myName","myAddress"};/*定義屬性的 GETTER*/static JSBool GetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp){ if (JSVAL_IS_INT(id)) { switch (JSVAL_TO_INT(id)) { case MY_NAME: *vp=STRING_TO_JSVAL (JS_NewStringCopyZ (cx,m_ainfo.name)); break; case MY_ADDRESS: *vp=STRING_TO_JSVAL (JS_NewStringCopyZ (cx,m_ainfo.addr)); break; } } return JS_TRUE;}/*定義屬性的SETTER*/static JSBool SetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp){ if (JSVAL_IS_INT(id)) { switch (JSVAL_TO_INT(id)) { case MY_NAME: strncpy (m_ainfo.name, JS_GetStringBytes (jss), 15); break; case MY_ADDRESS: strncpy (m_ainfo.addr, JS_GetStringBytes (jss), 63); break; } } return JS_TRUE;}/*定義print方法*/static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ fprintf(stdout,"My Name is %s.\nMy Addr is %s.\n",m_ainfo.name,m_ainfo.addr); return JS_TRUE;}void main(){ JSString* jss; char buf[5120]; int len; jsval rval; JSRuntime *rt; JSContext *cx; JSObject *globalObj,*PeopleObj; JSClass global_class = { "global",0, JS_PropertyStub, JS_PropertyStub,JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub,JS_ConvertStub, JS_FinalizeStub };/*定義People類的屬性數組*/static JSPropertySpec PeopleProperties[] = { {"name", MY_NAME, JSPROP_ENUMERATE }, {"address", MY_ADDRESS, JSPROP_ENUMERATE }, {0} } ;/*定義People類的方法數組*/static JSFunctionSpec PeopleMethods[] ={ {"print", PeoplePrint, 0}, {0} };/*定義People類*/static JSClass PeopleClass = { "people",0, JS_PropertyStub,JS_PropertyStub, GetPeopleProperty, SetPeopleProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub}; typedef struct{} /* 初始化JS RunTime,返回結果給rt */rt = JS_Init(1000000L); if (!rt)return; /* 建立一個上下文,並將其與JS RunTime關聯起來 */ cx = JS_NewContext(rt, 5120); if (!cx)return; /* 建立全域對象 */ if (!(globalObj = JS_NewObject (cx, &global_class, NULL, NULL)))return; /* 執行個體化內建對象和全域對象*/JS_InitStandardClasses (cx, globalObj);/*執行個體化People對象*/PeopleObj = JS_DefineObject (cx, globalObj, "People", &PeopleClass, 0,JSPROP_ENUMERATE);/*建立對象的屬性*/JS_DefineProperties (cx,PeopleObj, PeopleProperties);/*建立對象的方法*/JS_DefineFunctions (cx,PeopleObj, PeopleMethods);FILE* fp;/*開啟檔案,讀入指令碼*/ if (!(fp = fopen ("test.js", "r")))return; len = fread (buf, 1, 5120, fp); fclose (fp); if (len <= 0)return;/*執行一段指令碼*/ JS_EvaluateScript (cx, globalObj, buf, len, "", 1, &rval); jss = JS_ValueToString (cx, rval); fprintf(stdout,"The result is: %s",JS_GetStringBytes (jss));/*釋放上下文*/JS_DestroyContext(cx);/*釋放RunTime*/JS_DestroyRuntime(rt);return;} |
參考資料
作者:唐新華
原文出處:http://www.ibm.com/developerworks/cn/linux/shell/js/js_engine/index.html