日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++使用V8

發(fā)布時(shí)間:2024/4/15 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++使用V8 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:http://www.codeproject.com/KB/library/Using_V8_Javascript_VM.aspx

介紹

誰不想知道虛擬機(jī)是怎樣工作的?不過,比起自己寫一個(gè)虛擬機(jī),更好的辦法是使用大公司的產(chǎn)品。在這篇文章中,我將介紹如何在你的程序中使用V8——谷歌瀏覽器(Chrome)所使用的開源JavaScript引擎。

背景

這里的代碼使用V8作為嵌入庫來執(zhí)行JavaScript代碼。要取得庫源碼和其它信息,可以瀏覽V8開發(fā)者頁面。想有效地應(yīng)用V8,你需要了解C/C++JavaScript

使用

我們來看看演示中有哪些東西:

·???????????????????? 如何使用V8API來執(zhí)行JavaScript腳本。

·???????????????????? 如何存取腳本中的整數(shù)和字符串。

·???????????????????? 如何建立可被腳本調(diào)用的自定義函數(shù)。

·???????????????????? 如何建立可被腳本調(diào)用的自定義類。

首先,我們一起了解一下怎樣初始化V8。這是嵌入V8引擎的簡單例子:

1.??????????????? #include <v8.h>

2.??????????????? using namespace v8;

3.??????????????? int main(int argc, char* argv[]) {

4.??????????????? ? // Create a stack-allocated handle scope.

5.??????????????? ? HandleScope handle_scope;

6.??????????????? ? // Create a new context.

7.??????????????? ? Handle<Context> context = Context::New();

8.??????????????? ? // Enter the created context for compiling and

9.??????????????? ? // running the hello world script.

10.??????????? ? Context::Scope context_scope(context);

11.??????????? ? // Create a string containing the JavaScript source code.

12.??????????? ? Handle<String> source = String::New("'Hello' + ', World!'");

13.??????????? ? // Compile the source code.

14.??????????? ? Handle<Script> script = Script::Compile(source);

15.??????????? ? // Run the script to get the result.

16.??????????? ? Handle<Value> result = script->Run();

17.??????????? ? // Convert the result to an ASCII string and print it.

18.??????????? ? String::AsciiValue ascii(result);

19.??????????? ? printf("%s ", *ascii);

20.??????????? ? return 0;

21.??????????? }

好了,不過這還不能說明怎樣讓我們控制腳本中的變量和函數(shù)。

全局模型(The Global Template

首先,我們需要一個(gè)全局模型來掌控我們所做的修改:

1.??????????????? v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();

這里建立了一個(gè)新的全局模型來管理我們的上下文(context)和定制。在V8里,每個(gè)上下文是分開的,它們有自己的全局模型。一個(gè)上下文就是一個(gè)獨(dú)立的執(zhí)行環(huán)境,相互之間沒有關(guān)聯(lián),JavaScript運(yùn)行于其中一個(gè)實(shí)例之中。

自定義函數(shù)

接下來,我們加入一個(gè)名為"plus"的自定義函數(shù):

1.??????????????? // plus function implementation - Add two numbers

2.??????????????? v8::Handle<v8::Value> Plus(const v8::Arguments& args)

3.??????????????? {

4.??????????????? ??? unsigned int A = args[0]->Uint32Value();

5.??????????????? ??? unsigned int B = args[1]->Uint32Value();

6.??????????????? ??? return v8_uint32(A +? B);

7.??????????????? }

8.??????????????? //...

9.??????????????? //associates plus on script to the Plus function

10.??????????? global->Set(v8::String::New("plus"), v8::FunctionTemplate::New(Plus));

自定義函數(shù)必須以const v8::Arguments&作為參數(shù)并返回v8::Handle<v8::Value>。我們把這個(gè)函數(shù)加入到模型中,關(guān)聯(lián)名稱"plus"到回調(diào)Plus。現(xiàn)在,在腳本中每次調(diào)用"plus",我們的Plus函數(shù)就會(huì)被調(diào)用。這個(gè)函數(shù)只是返回兩個(gè)參數(shù)的和。

現(xiàn)在我們可以在JavaScript里使用這個(gè)自定義函數(shù)了:

plus(120,44);?

在腳本里也可以得到函數(shù)的返回值:

x = plus(1,2);

if( x == 3){

?? // do something important here!

}

訪問器(Accessor)——存取腳本中的變量

現(xiàn)在,我們可以建立函數(shù)了...不過如果我們可以在腳本外定義一些東西豈不是更酷?Let's do it! V8里有個(gè)東東稱為存取器(Accessor),使用它,我們可以關(guān)聯(lián)一個(gè)名稱到一對(duì)Get/Set函數(shù)上,V8會(huì)用它來存取腳本中的變量。

1.??????????????? global->SetAccessor(v8::String::New("x"), XGetter, XSetter);

這行代碼關(guān)聯(lián)名稱"x"XGetterXSetter函數(shù)。這樣在腳本中每次讀取到"x"變量時(shí)都會(huì)調(diào)用XGetter,每次更新"x"變量時(shí)會(huì)調(diào)用XSetter。下面是這兩個(gè)函數(shù)的代碼:

1.??????????????? //the x variable!

2.??????????????? int x;

3.??????????????? //get the value of x variable inside javascript

4.??????????????? static v8::Handle<v8::Value> XGetter( v8::Local<v8::String> name,

5.??????????????? ????????????????? const v8::AccessorInfo& info) {

6.??????????????? ? return? v8::Number::New(x);

7.??????????????? }

8.??????????????? //set the value of x variable inside javascript

9.??????????????? static void XSetter( v8::Local<v8::String> name,

10.??????????? ?????? v8::Local<v8::Value> value, const v8::AccessorInfo& info) {

11.??????????? ? x = value->Int32Value();

12.??????????? }

XGetter里我們把"x"轉(zhuǎn)換成V8喜歡的數(shù)值類型。XSetter里,我們把傳入的參數(shù)轉(zhuǎn)換成整數(shù),Int32Value是基本類型轉(zhuǎn)換函數(shù)的一員,還有NumberValue對(duì)應(yīng)doubleBooleanValue對(duì)應(yīng)bool,等。

現(xiàn)在,我們可以為字符串做相同的操作:

1.??????????????? //the username accessible on c++ and inside the script

2.??????????????? char username[1024];

3.??????????????? //get the value of username variable inside javascript

4.??????????????? v8::Handle<v8::Value> userGetter(v8::Local<v8::String> name,

5.??????????????? ?????????? const v8::AccessorInfo& info) {

6.??????????????? ??? return v8::String::New((char*)&username,strlen((char*)&username));

7.??????????????? }

8.??????????????? //set the value of username variable inside javascript

9.??????????????? void userSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value,

10.??????????? ??? const v8::AccessorInfo& info) {

11.??????????? ??? v8::Local<v8::String> s = value->ToString();

12.??????????? ??? s->WriteAscii((char*)&username);

13.??????????? }

對(duì)于字符串,有一點(diǎn)點(diǎn)不同,"userGetter"XGetter做的一樣,不過userSetter要先用ToString方法取得內(nèi)部字符串,然后用WriteAscii函數(shù)把內(nèi)容寫到我們指定的內(nèi)存中。現(xiàn)在,加入存取器:

1.??????????????? //create accessor for string username

2.??????????????? global->SetAccessor(v8::String::New("user"),userGetter,userSetter);

打印輸出

"print"函數(shù)是另一個(gè)自定義函數(shù),它通過"printf"輸出所有的參數(shù)內(nèi)容。和之前的"plus"函數(shù)一樣,我們要在全局模型中注冊(cè)這個(gè)函數(shù):

1.??????????????? //associates print on script to the Print function

2.??????????????? global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));

實(shí)現(xiàn)"print"函數(shù)

1.??????????????? // The callback that is invoked by v8 whenever the JavaScript 'print'

2.??????????????? // function is called. Prints its arguments on stdout separated by

3.??????????????? // spaces and ending with a newline.

4.??????????????? v8::Handle<v8::Value> Print(const v8::Arguments& args) {

5.??????????????? ??? bool first = true;

6.??????????????? ??? for (int i = 0; i < args.Length(); i++)

7.??????????????? ??? {

8.??????????????? ??????? v8::HandleScope handle_scope;

9.??????????????? ??????? if (first)

10.??????????? ??????? {

11.??????????? ??????????? first = false;

12.??????????? ??????? }

13.??????????? ??????? else

14.??????????? ??????? {

15.??????????? ??????????? printf(" ");

16.??????????? ??????? }

17.??????????? ??????? //convert the args[i] type to normal char* string

18.??????????? ??????? v8::String::AsciiValue str(args[i]);

19.??????????? ??????? printf("%s", *str);

20.??????????? ??? }

21.??????????? ??? printf(" ");

22.??????????? ??? //returning Undefined is the same as returning void...

23.??????????? ??? return v8::Undefined();

24.??????????? }

這里,為每個(gè)參數(shù)都構(gòu)建了v8::String::AsciiValue對(duì)象:數(shù)據(jù)的char*表示。通過它,我們就可以把所有類型都轉(zhuǎn)換成字符串并打印出來。

JavaScript演示

在演示程序里,我們有一個(gè)簡單的JavaScript腳本,調(diào)用了迄今為止我們建立的所有東西:

print("begin script");

print(script executed by? + user);

if ( user == "John Doe"){

??? print("/tuser name is invalid. Changing name to Chuck Norris");

??? user = "Chuck Norris";

}

print("123 plus 27 = " + plus(123,27));

x = plus(3456789,6543211);

print("end script");

?

存取C++對(duì)象

為我們的類準(zhǔn)備環(huán)境

如果用C++把一個(gè)類映射到JavaScript中去?放一個(gè)演示用的類上來先:

1.??????????????? //Sample class mapped to v8

2.??????????????? class Point

3.??????????????? {

4.??????????????? public:

5.??????????????? ??? //constructor

6.??????????????? ??? Point(int x, int y):x_(x),y_(y){}

7.??????????????? ?

8.??????????????? ??? //internal class functions

9.??????????????? ??? //just increment x_

10.??????????? ??? void Function_A(){++x_;??? }

11.??????????? ?

12.??????????? ??? //increment x_ by the amount

13.??????????? ??? void Function_B(int vlr){x_+=vlr;}

14.??????????? ?

15.??????????? ??? //variables

16.??????????? ??? int x_;

17.??????????? };

為了把這個(gè)類完全嵌入腳本中,我們需要映射類成員函數(shù)和類成員變量。第一步是在我們的上下文中映射一個(gè)類模型(class template):

1.??????????????? Handle<FunctionTemplate> point_templ = FunctionTemplate::New();

2.??????????????? point_templ->SetClassName(String::New("Point"));

我們建立了一個(gè)"函數(shù)"模型[FunctionTemplate],但這里應(yīng)該把它看成類。

然后,我們通過原型模型(Prototype Template)加入內(nèi)建的類方法:

1.??????????????? Handle<ObjectTemplate> point_proto = point_templ->PrototypeTemplate();

2.??????????????? point_proto->Set("method_a", FunctionTemplate::New(PointMethod_A));

3.??????????????? point_proto->Set("method_b", FunctionTemplate::New(PointMethod_B));

接下來,類有了兩個(gè)方法和對(duì)應(yīng)的回調(diào)。但它們目前只在原型中,沒有類實(shí)例訪問器我們還不能使用它們。

1.??????????????? Handle<ObjectTemplate> point_inst = point_templ->InstanceTemplate();

2.??????????????? point_inst->SetInternalFieldCount(1);

SetInternalFieldCount函數(shù)為C++類建立一個(gè)空間(后面會(huì)用到)

現(xiàn)在,我們有了類實(shí)例,加入訪問器以訪問內(nèi)部變量:

1.??????????????? point_inst->SetAccessor(String::New("x"), GetPointX, SetPointX);

接著,土壤準(zhǔn)備好了,開始播種:

1.??????????????? Point* p = new Point(0, 0);

新對(duì)象建立好了,目前只能在C++中使用,要放到腳本里,我們還要下面的代碼:

1.??????????????? Handle<Function> point_ctor = point_templ->GetFunction();

2.??????????????? Local<Object> obj = point_ctor->NewInstance();

3.??????????????? obj->SetInternalField(0, External::New(p));

好了,GetFunction返回一個(gè)point構(gòu)造器(JavaScript方面), 通過它,我們可以用NewInstance生成一個(gè)新的實(shí)例。然后,用Point對(duì)象指針設(shè)置我們的內(nèi)部域(我們前面用SetInternalFieldCount建立的空間)JavaScript可以通過這個(gè)指針存取對(duì)象。

還少了一步,我們只有類模型和實(shí)例,但還缺一個(gè)名字來存取它:

1.??????????????? context->Global()->Set(String::New("point"), obj);

JavaScript里訪問類方法

最后,我們還要解釋一下怎樣在Point類中訪問Function_A...

讓我們看看PointMethod_A回調(diào):

1.??????????????? Handle<Value> PointMethod_A(const Arguments& args)

2.??????????????? {

3.??????????????? ??? Local<Object> self = args.Holder();

4.??????????????? ??? Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));

5.??????????????? ??? void* ptr = wrap->Value();

6.??????????????? ??? static_cast<Point*>(ptr)->Function_A();

7.??????????????? ??? return Integer::New(static_cast<Point*>(ptr)->x_);

8.??????????????? }

和普通訪問器一樣,我們必須處理參數(shù)。要訪問我們的類,必須從內(nèi)部域(第一個(gè))中取得類指針。把內(nèi)部域映射到"wrap"之后,我們使用它的"value"方法取得類指針。

其它

希望這篇文章對(duì)你有所幫助,如果發(fā)現(xiàn)文章有誤,請(qǐng)不吝賜教

?

?

總結(jié)

以上是生活随笔為你收集整理的C++使用V8的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。