本文檔提供了一個(gè)JavaScript(JS)引擎的C語(yǔ)言實(shí)現的概述,他介紹了你如何在你的應用程序中嵌入腳本引擎來(lái)讓它們可以使用JS。有兩大理由讓你在應用程序中嵌入JS引擎:使用腳本來(lái)自動(dòng)操作你的應用程序;同時(shí)使用JS引擎和腳本無(wú)論何時(shí)都可以提供跨平臺的功能并消除了應用程序解決方案對平臺的依賴(lài)性。
本JS引擎支持從JS 1.0版到JS1.4。JS 1.3和更高版本符合ECMAScript-262規范。JS引擎解析、編譯和執行包含JS語(yǔ)句和函數的腳本。這個(gè)引擎可以處理要用來(lái)執行腳本的JS數據類(lèi)型和對象內存分配,同時(shí)它可以清除——垃圾回收——內存中已經(jīng)不需要的數據類(lèi)型和對象。
通常,你將JS引擎作為一個(gè)共享的資源進(jìn)行構建。例如,在Windows和Windows NT上,這個(gè)引擎是一個(gè)DLL文件,在Unix上是一個(gè)共享庫。然后你把你的應用程序和他連接,同時(shí)嵌入式JS引擎應用程序編程接口(API)就可以在你的應用程序中調用了。JS引擎的API提供了以下幾種分類(lèi)的函數:
數據類(lèi)型操作
運行時(shí)控制
類(lèi)和對象創(chuàng )生的維護
函數和腳本執行
字符串處理
錯誤處理
安全性控制
調試支持
你在每個(gè)嵌入了JS調用的應用程序中將會(huì )用到這些功能分類(lèi)中的某些部分,象運行時(shí)控制和數據類(lèi)型操作。例如,在你調用其他JS功能之前,你必須通過(guò)調用 JS_NewRuntime 函數來(lái)新建和初始化JS引擎。其他功能分類(lèi),像安全控制,提供一些可選的特性,你可以根據需要在你的應用程序中使用它們。
從概念上來(lái)講,JS引擎在你的系統上是一個(gè)共享資源。通過(guò)在你的應用程序中嵌入引擎API命令你可以向JS引擎傳遞處理的請求。這個(gè)引擎,反過(guò)來(lái),處理你的請求,并把返回值或者狀態(tài)信息返回給你的應用程序。圖1.1描述了它們一般的關(guān)系:
圖 1.1

例如,假設你正在使用JS引擎來(lái)使你的應用程序能通過(guò)JS腳本自動(dòng)運行,同時(shí)假設你的應用程序運行一個(gè)腳本來(lái)對一個(gè)用戶(hù)進(jìn)行身份驗證并且設置一個(gè)用戶(hù)對這個(gè)應用程序的訪(fǎng)問(wèn)權限。首先,你的應用程序可能新建一個(gè)代表用戶(hù)的自定義JS對象,包括了用戶(hù)的名字、ID、訪(fǎng)問(wèn)權限和一個(gè)可能的用戶(hù)擁有權限在應用程序中使用的函數的列表。
在這個(gè)情況下,你的應用程序給JS引擎發(fā)送的的第一個(gè)請求可能是對 JS_NewObject 的調用來(lái)新建一個(gè)自定義對象。當JS引擎新建了這個(gè)對象,他返回一個(gè)指針給你的應用程序。你的應用程序可以再次調用JS引擎來(lái)執行使用這個(gè)對象的腳本。例如,在建立了用戶(hù)對象之后,你的應用程序會(huì )立刻給 JS_EvaluateScript 傳遞一個(gè)腳本來(lái)立刻編譯執行。那個(gè)腳本可以獲得并驗證用戶(hù)信息,然后建立用戶(hù)對其他應用程序特性的訪(fǎng)問(wèn)權限。
事實(shí)上,你的應用程序和JS引擎之間的關(guān)系遠比圖1.1中顯示的要復雜的多。例如,它假設你已經(jīng)為你的平臺構建了JS引擎。它還假設你的應用程序包含了 jsapi.h 還假設應用程序對引擎進(jìn)行的第一個(gè)調用已經(jīng)初始化了JS運行時(shí)。
當JS引擎接受到了一個(gè)初始化的請求時(shí),他會(huì )為JS運行時(shí)分配內存。圖1.2描述了這個(gè)過(guò)程:
圖 1.2

這個(gè)運行時(shí)是一個(gè)內存空間,在其中可以維護你的應用程序所使用的變量、對象和上下文。一個(gè)上下文是指,針對JS引擎所使用的線(xiàn)程的腳本執行狀態(tài)。每個(gè)同時(shí)存在的腳本或者線(xiàn)程都必須有它自己的上下文。一個(gè)單獨的JS運行時(shí)可以包含很多上下文、對象和變量。
幾乎所有的JS引擎調用都要求有一個(gè)上下文的參數,所以在創(chuàng )建了運行時(shí)之后你的應用程序首先要做的一件事情是調用 JS_NewContext 來(lái)至少創(chuàng )建一個(gè)上下文。實(shí)際你需要的上下文數量由你的應用程序中所期望同時(shí)運行的腳本的數量決定。從另一方面說(shuō),如果同一時(shí)間只有一個(gè)腳本被編譯執行,那么你就知需要建立單獨的一個(gè)上下文,你可以對每個(gè)腳本重復使用它。
在你新建了上下文之后,你會(huì )通常想要初始化引擎內置的JS對象,可以通過(guò)調用 JS_InitStandardClasses 實(shí)現。內置的對象有 Array , Boolean , Date , Math , Number ,和 String 字符串對象,大多數腳本都會(huì )用到。
大多數應用程序也要用到自定義JS對象。這些對象是特定于你的應用程序的。他們通常代表了數據結構和應用程序中腳本使用的方法。要新建一個(gè)自定義對象,你要組裝一個(gè)JS類(lèi)來(lái)生成這個(gè)對象,調用 JS_InitClass 來(lái)在運行時(shí)設立這個(gè)類(lèi),然后調用 JS_NewObject 來(lái)在引擎中新建你這個(gè)自定義對象的實(shí)例。最后,如果你的對象有一些屬性,你也許要通過(guò)調用 JS_SetProperty 來(lái)設置他們的默認值。
即使你在創(chuàng )建一個(gè)對象的時(shí)候給JS引擎傳遞了一個(gè)特定的上下文,最后這個(gè)對象還是獨立于這個(gè)上下文存在的。任何腳本都可以和任意上下文相關(guān)聯(lián)來(lái)訪(fǎng)問(wèn)任何對象。圖1.3描述了腳本和運行時(shí)、上下文以及對象之間的關(guān)系。
圖 1.3

如圖1.3所示,腳本和上下文完全是互相獨立存在的及時(shí)他們可以訪(fǎng)問(wèn)相同的對象。在給定的運行時(shí)中,一個(gè)應用程序可以任意未分配的上下文來(lái)訪(fǎng)問(wèn)任何對象。也可能有時(shí)你想確保能為獨占的使用而保留某些上下文和對象。在這些情況下,給你的應用程序新建單獨的運行時(shí):一個(gè)針對共享上下文和對象,另一個(gè)(或者更多的,取決于你的應用程序的需求)針對私有的運行時(shí)和對象。
注意: 同一時(shí)間只能有一個(gè)線(xiàn)程被授權訪(fǎng)問(wèn)特定上下文。
在你可以在你的應用程序中使用JS之前,你必須將JS引擎構建成一個(gè)可共享的庫。在大多數情況下,引擎代碼已經(jīng)包括了Make文件來(lái)自動(dòng)構建。
例如,在Unix下, js 源代碼目錄包括了一個(gè)基本的Gnu Make文件—— Makefile.ref 和一個(gè) config 目錄。 config 目錄包括了平臺特定的 .mk 文件來(lái)配合 Makefile.ref 對你的環(huán)境進(jìn)行構建。在Windows NT下,NMake文件是 js.mak 。
請閱讀源代碼目錄中任何的 readme 文件,也許其中包括了和更新的編譯指導或者其他信息。
如果要讓你的應用程序可以執行JS,就要在你的應用程序代碼中嵌入合適的引擎。嵌入一般有五步:
在你的C模塊中加入 #include jsapi.h 來(lái)確保編譯器知道有哪些引擎的API可以調用。極少部分特殊的JS引擎工作時(shí)會(huì )要求你包含額外的頭文件。例如,要在你的應用程序中調用JS調試器,你要在合適的模塊里面包含 jsdbgapi.h 。
大部分在JS源代碼中的其它的頭文件 不 應該被引用。這樣做可能會(huì )使你的程序依賴(lài)于引擎內部的接口,而這些接口可能隨著(zhù)版本發(fā)布而更改。
在你的應用程序中提供支持結構和變量聲明。例如,如果你打算給JS引擎傳遞一個(gè)腳本呢,提供一個(gè)字符串變量保存了你的應用程序的腳本的版本的文字信息。使用 jsapi.h 中定義的JS數據類(lèi)型來(lái)聲明結構和變量。
使用JavaScript編寫(xiě)特定應用的對象。這些對象常常會(huì )與操作在你C程序中的結構的結構和方法進(jìn)行通訊,特別是如果你在使用JS引擎來(lái)自動(dòng)操作你的應用程序。
在程序代碼中嵌入合適的JS引擎API調用和變量引用,包括初始化內置JS對象,和創(chuàng )建組成任何應用程序要用的自定義對象。
大多數JS引擎調用都會(huì )返回一個(gè)值。如果這個(gè)值是零或者空,它通常表示一個(gè)錯誤的情況發(fā)生了。如果值非零,它一般表示成功;在這些情況下,返回的值常常會(huì )是你的程序需要使用的指針,或者存起來(lái)留以后引用。很重要的是,你的程序至少應該每次檢查JS調用返回的值。
以下代碼片斷描述了嵌入使用的大部分過(guò)程,除了JS腳本的建立,這點(diǎn)也不在本文的介紹范圍之內。如要查詢(xún)有關(guān)創(chuàng )建腳本的信息——JavaScript這個(gè)語(yǔ)言——請看 客戶(hù)端 JavaScript 指導 ,如果要得到關(guān)于編寫(xiě)服務(wù)器端對象,見(jiàn) 服務(wù)器端 JavaScript 指導 。
.
.
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 包含JS引擎API頭文件 */
#include "jsapi.h"
.
.
.
/* 主程序建立全局JS變量,包括運行時(shí),
* 一個(gè)上下文,和一個(gè)全局對象,然后初始化JS運行時(shí),
* 并創(chuàng )建一個(gè)上下文. */
int main(int argc, char **argv)
{
int c, i;
/*建立全局的JS變量,包括全局和自定義對象 */
JSVersion version;
JSRuntime *rt;
JSContext *cx;
JSObject *glob, *it;
JSBool builtins;
/* 初始化JS運行時(shí),并返回結果給rt */
rt = JS_NewRuntime(8L * 1024L * 1024L);
/* 如果rt沒(méi)有值,結束程序 */
if (!rt)
return 1;
/* 新建一個(gè)上下文并且把它和JS運行時(shí)相關(guān)聯(lián) */
cx = JS_NewContext(rt, 8192);
/* 如果cx沒(méi)有值,在此結束程序 */
if (cx == NULL)
return 1;
/* 新建全局對象 */
glob = JS_NewObject(cx, clasp, NULL, NULL);
/* 初始化內置JS對象和全局對象 */
builtins = JS_InitStandardClasses(cx, glob);
.
.
.
return 0;
}
這個(gè)范例代碼十分簡(jiǎn)單,它描述了嵌入JS引擎調用所必須的關(guān)鍵元素。如果想要更完整的例子——也就是以上這段代碼片斷的出處——參見(jiàn) js.c ,這個(gè)范例應用的源代碼是包含在JS引擎的源代碼中的。
聯(lián)系客服