本篇內容介紹了“在C++中怎么執(zhí)行JavaScript程序”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
創(chuàng)新互聯(lián)建站網(wǎng)站建設服務商,為中小企業(yè)提供成都網(wǎng)站設計、做網(wǎng)站服務,網(wǎng)站設計,網(wǎng)站托管維護等一站式綜合服務型公司,專業(yè)打造企業(yè)形象網(wǎng)站,讓您在眾多競爭對手中脫穎而出創(chuàng)新互聯(lián)建站。SpiderMonkey是Mozilla項目的一部分,用C語言寫成,是負責執(zhí)行JavaScript腳本的引擎。另外還有一個叫Rhino的Java引擎。
SpiderMonkey的新版本可在這里下載。它是以源代碼形式發(fā)布的,因此你必須自己編譯它。Visual C++用戶可以在src目錄下找到Workspace項目工程文件來編譯,編譯結果會產(chǎn)生一個叫'js32.dll'的dll文件。
SpiderMonkey也可以在Macintosh和Unix上使用。
初始化一個JavaScript runtime可用JS_NewRuntime方法,該方法將為runtime分配內存,同時還得指定一個字節(jié)數(shù),當內存分配超過這個數(shù)字時垃圾收集器會自動運行。
JSRuntime *rt = JS_NewRuntime(1000000L);
if ( rt == NULL )
{
// Do some error reporting
}
Context指明了腳本運行所需的棧大小,即分配給腳本執(zhí)行棧的私有內存數(shù)量。每個腳本都和它自己的context相關聯(lián)。
當一個context正在被某個腳本或線程使用時,其他腳本或線程不能使用該context。不過在腳本或線程結束時,該context可以被下一個腳本或線程重用。
創(chuàng)建一個新context可用JS_NewContext方法。context必須關聯(lián)到一個runtime,調用JS_NewContext方法時還必須指定棧的大小。
JSContext *cx = JS_NewContext(m_rt, 8192);
if ( cx == NULL )
{
// Do some error reporting
}
在一個腳本開始運行前,必須初始化一些大多數(shù)腳本會用到的通用的JavaScript函數(shù)和內置(build-in)類對象。
全局對象是在一個JSClass結構中描述的。該結構可以按以下方式初始化:
JSClass globalClass =
{
"Global", 0,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub
};
現(xiàn)在創(chuàng)建和初始化這個全局對象:JSObject *globalObj = JS_NewObject(cx, &globalClass, 0, 0); JS_InitStandardClasses(cx, globalObj);
執(zhí)行腳本的一種途徑是使用JS_EvaluateScript方法:
std::string script = "var today = Date(); today.toString();"
jsval rval;
uintN lineno = 0;
JSBool ok = JS_EvaluateScript(cx, globalObj, script.c_str(),
script.length(), "script", lineno, &rval);
在這個腳本中,如果運行正確的話當天數(shù)據(jù)會保存在rval中。rval包含最后一個執(zhí)行函數(shù)的結果。JS_EvaluteScript返回JS_TRUE代表執(zhí)行成功,返回JS_FALSE則代表有錯誤發(fā)生。
從rval得到相應的字符串值可以用下面的方法。在這里我不想解釋所有細節(jié),想獲得更詳細的信息請自己查API文檔。
JSString *str = JS_ValueToString(cx, rval);
std::cout << JS_GetStringBytes(str);
程序結束前必須對腳本引擎做一些清理工作:JS_DestroyContext(cx); JS_DestroyRuntime(rt);
這個例子中用到的類定義如下:
class Customer
{
public:
int GetAge() { return m_age; }
void SetAge(int newAge) { m_age = newAge; }
std::string GetName() { return m_name; }
void SetName(std::string newName) { m_name = newName; }
private:
int m_age;
std::string m_name;
};
從Customer類派生一個你想在JavaScript中用的新的C++類,或者創(chuàng)建一個包含一個Customer類型成員變量的新類。
給JavaScript用的類得有一個JSClass結構,為此得創(chuàng)建一個JSClass類型的靜態(tài)成員變量,該變量會被其他類用到,因此還得把它聲明為public變量。別的類可以用該結構來判斷對象的類型(見JS_InstanceOf API)。
// JSCustomer.h
class JSCustomer
{
public:
JSCustomer() : m_pCustomer(NULL)
{
}
~JSCustomer()
{
delete m_pCustomer;
m_pCustomer = NULL;
}
static JSClass customerClass;
protected:
void setCustomer(Customer *customer)
{
m_pCustomer = customer;
}
Customer* getCustomer()
{
return m_pCustomer;
}
private:
Customer *m_pCustomer;
};
該JSClass結構里包含了JavaScript類的名字、標志位以及給腳本引擎用的回調函數(shù)的名字。舉個例子,腳本引擎使用回調函數(shù)從類中獲取某個屬性值。
在C++類的實現(xiàn)文件中定義JSClass結構如下:
// JSCustomer.cpp
JSClass JSCustomer::customerClass =
{
"Customer", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
JSCustomer::JSGetProperty, JSCustomer::JSSetProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JSCustomer::JSDestructor
};
用到的回調函數(shù)是JSCustomer::JSGetProperty,JSCustomer::JSSetProperty和JSCustomer::JSDestructor。腳本引擎調用JSGetProperty獲取屬性值,調用JSSetProperty設置屬性值,調用JSDestructor析構JavaScript對象。
JSCLASS_HAS_PRIVATE標志位會讓腳本引擎分配一些內存,這樣你可以在JavaScript對象中附加一些自定義數(shù)據(jù),比如可以用它來保存類指針。
回調函數(shù)以C++的類靜態(tài)成員函數(shù)方式存在:
static JSBool JSGetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool JSSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool JSConstructor(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval);
static void JSDestructor(JSContext *cx, JSObject *obj);
創(chuàng)建另外一個叫JSInit的靜態(tài)方法,見下面的例子,該方法將在應用程序創(chuàng)建JavaScript runtime時被調用。
static JSObject *JSInit(JSContext *cx, JSObject *obj, JSObject *proto);
JSInit方法的實現(xiàn)大約如下:
JSObject *JSCustomer::JSInit(JSContext *cx, JSObject *obj, JSObject *proto)
{
JSObject *newObj = JS_InitClass(cx, obj, proto, &customerClass,
JSCustomer::JSConstructor, 0,
JSCustomer::customer_properties, JSCustomer::customer_methods,
NULL, NULL);
return newObj;
}
對象在腳本中被具象化(譯注:instantiated,簡而言之就是對象new出來的時候)的時候,靜態(tài)方法JSConstructor會被調用。在這個方法中可以用JS_SetPrivate API給該對象附加一些自定義數(shù)據(jù)。
JSBool JSCustomer::JSConstructor(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
{
JSCustomer *p = new JSCustomer();
p->setCustomer(new Customer());
if ( ! JS_SetPrivate(cx, obj, p) )
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
JSConstructor構造方法可以帶多個參數(shù),用來初始化類。目前為止已經(jīng)在堆上創(chuàng)建了一個指針,還需要一種途徑來銷毀它,這可以通過JS_Destructor完成:
void JSCustomer::JSDestructor(JSContext *cx, JSObject *obj)
{
JSCustomer *p = JS_GetPrivate(cx, obj);
delete p;
p = NULL;
}
添加一個JSPropertySpec類型的靜態(tài)成員數(shù)組來存放屬性信息,同時定義屬性ID的枚舉變量。
static JSPropertySpec customer_properties[];
enum
{
name_prop,
age_prop
};
在實現(xiàn)文件中如下初始化該數(shù)組:
JSPropertySpec JSCustomer::customer_properties[] =
{
{ "name", name_prop, JSPROP_ENUMERATE },
{ "age", age_prop, JSPROP_ENUMERATE },
{ 0 }
};
數(shù)組的最后一個元素必須為空,其中每個元素是一個帶有3個元素的數(shù)組。第一個元素是給JavaScript用的名字。第二個元素是該屬性的ID,將傳遞給回調函數(shù)。第三個元素是標志位,JSPROP_ENUMERATE代表腳本在枚舉Customer對象的所有屬性時可以看到該屬性,也可以指定JSPROP_READONLY來表明該屬性不允許被腳本程序改變。
現(xiàn)在可以實現(xiàn)該屬性的getting和setting回調函數(shù)了:
JSBool JSCustomer::JSGetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
if (JSVAL_IS_INT(id))
{
Customer *priv = (Customer *) JS_GetPrivate(cx, obj);
switch(JSVAL_TO_INT(id))
{
case name_prop:
break;
case age_prop:
*vp = INT_TO_JSVAL(priv->getCustomer()->GetAge());
break;
}
}
return JS_TRUE;
}
JSBool JSCustomer::JSSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
if (JSVAL_IS_INT(id))
{
Customer *priv = (Customer *) JS_GetPrivate(cx, obj);
switch(JSVAL_TO_INT(id))
{
case name_prop:
break;
case age_prop:
priv->getCustomer()->SetAge(JSVAL_TO_INT(*vp));
break;
}
}
return JS_TRUE;
}
建議在屬性的回調函數(shù)中返回JS_TRUE。如果返回JS_FALSE,則當該屬性在對象中沒找到時(腳本引擎)不會進行搜索。
創(chuàng)建一個JSFunctionSpec類型的靜態(tài)成員數(shù)組:
static JSFunctionSpec customer_methods[];
在實現(xiàn)文件中如下初始化該數(shù)組:
JSFunctionSpec wxJSFrame::wxFrame_methods[] =
{
{ "computeReduction", computeReduction, 1, 0, 0 },
{ 0 }
};
最后一個元素必須為空,其中每個元素是一個帶有5個元素的數(shù)組。第一個元素是給腳本程序用的方法名稱。第二個是一個全局或者靜態(tài)成員函數(shù)的名稱。第三個是該方法的參數(shù)個數(shù)。最后兩個可以忽略。
在類中創(chuàng)建一個靜態(tài)方法:
static JSBool computeReduction(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval);
該函數(shù)成功時返回JS_TRUE,否則返回JS_FALSE。注意真正的JavaScript方法的返回值保存在rval參數(shù)中。
該方法的一個實現(xiàn)例子:
JSBool JSCustomer::computeReduction(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
{
JSCustomer *p = JS_GetPrivate(cx, obj);
if ( p->getCustomer()->GetAge() < 25 )
*rval = INT_TO_JSVAL(10);
else
*rval = INT_TO_JSVAL(5);
return JS_TRUE;
}
下面的腳本使用了前面創(chuàng)建的對象:
var c = new Customer();
c.name = "Franky";
c.age = 32;
var reduction = c.computeReduction();
別忘了在創(chuàng)建context時初始化JavaScript對象:
JSObject *obj = JSCustomer::JSInit(cx, global);
“在C++中怎么執(zhí)行JavaScript程序”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質量的實用文章!