使用訪問(wèn)器訪問(wèn) C++ 對(duì)象
為我們的類設(shè)置環(huán)境
怎樣使用C++把一個(gè)類映射成為 JavaScript?首先來(lái)看看如下的例子:
//Sample class mapped to v8
class Point
{
public:
//constructor
Point(int x, int y):x_(x),y_(y){}
//internal class functions
//just increment x_
void Function_A(){++x_; }
//increment x_ by the amount
void Function_B(int vlr){x_+=vlr;}
//variables
int x_;
};
為了保證整個(gè)類映射后完全基于 JavaScript,我們對(duì)類的成員函數(shù)和變量都做映射。第一步,在上下文環(huán)境(context)中映射一個(gè)類模板:
Handle<FunctionTemplate> point_templ = FunctionTemplate::New();
point_templ->SetClassName(String::New("Point"));
從字面上似乎看出:我們只是創(chuàng)建了一個(gè)“函數(shù)(function)”模板,但實(shí)際上它能夠被看作一個(gè)類。它的名字是“Point”,我們將會(huì)在后面用到。
然后,通過(guò)訪問(wèn)原型(prototype) 類模板,我們能為這個(gè)類添加內(nèi)建的方法:
Handle<ObjectTemplate> point_proto = point_templ->PrototypeTemplate();
point_proto->Set("method_a", FunctionTemplate::New(PointMethod_A));
point_proto->Set("method_b", FunctionTemplate::New(PointMethod_B));
類能通過(guò)上面的代碼“知道”它有兩個(gè)方法。但這仍然是類的原型,我們必須要實(shí)例化這個(gè)類之后,才能使用這兩個(gè)方法。
Handle<ObjectTemplate> point_inst = point_templ->InstanceTemplate();
point_inst->SetInternalFieldCount(1);
SetInternalFieldCount 函數(shù)為類指針申請(qǐng)空間(在后面會(huì)再一次提到)。一旦有了類的實(shí)例,我們就能為類中的變量添加訪問(wèn)器了:
point_inst->SetAccessor(String::New("x"), GetPointX, SetPointX);
至此,舞臺(tái)算是搭好了,主角該上場(chǎng)了:
Point* p = new Point(0, 0);
新類已經(jīng)建好了,但只能在C++中訪問(wèn)。要對(duì)其進(jìn)行訪問(wèn),我們需要:
Handle<Function> point_ctor = point_templ->GetFunction();
Local<Object> obj = point_ctor->NewInstance();
obj->SetInternalField(0, External::New(p));
GetFunction 返回 point 的構(gòu)造器,有了它,我們可以使用 NewInstance 函數(shù)來(lái)創(chuàng)建一個(gè)新的實(shí)例。然后,使用類指針來(lái)設(shè)置內(nèi)部域(這個(gè)域的空間我們?cè)谇懊嬉呀?jīng)使用 SetInternalFieldCount 函數(shù)申請(qǐng)好了)。這樣一來(lái),JavaScript 就能通過(guò)指針訪問(wèn)該對(duì)象。
有一點(diǎn)我們漏掉了,我們想從 JavaScript 中訪問(wèn)它,但只有類模板和實(shí)例,沒(méi)有名字:
context->Global()->Set(String::New("point"), obj);
最后一步將“point”這個(gè)名字和 obj 實(shí)例聯(lián)系起來(lái)。到這里,我們僅僅是完成了在腳本中使用“point”名字來(lái)創(chuàng)建 Point 類的過(guò)程。
在 JavaScript 中訪問(wèn)類方法
這里講的并不是我們?cè)鯓釉?Point 類中訪問(wèn) Function_A……
先來(lái)看看回調(diào)函數(shù) PointMethod_A:
Handle<Value> PointMethod_A(const Arguments& args)
{
Local<Object> self = args.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
static_cast<Point*>(ptr)->Function_A();
return Integer::New(static_cast<Point*>(ptr)->x_);
}
和普通的訪問(wèn)器類似,我們需對(duì)參數(shù)進(jìn)行操作。而且,要能訪問(wèn)我們自己的類,還必須得從內(nèi)部域中獲取相關(guān)的類指針。在將內(nèi)部域映射到“wrap”之后,就可以通過(guò)獲取它的“值(Value)”來(lái)得到類指針,然后再進(jìn)行類型轉(zhuǎn)換。得到“point”類指針之后,可以通過(guò)它來(lái)調(diào)用 method_a ,method_a 來(lái)調(diào)用回調(diào)函數(shù) PointMethod_A。
示例 v8_embedded_demo_with_object.zip (Visual C++ Express 2008 )完整的包含了上述各個(gè)步驟。
最后,我非常希望這篇文章能對(duì)你有所幫助。如果感覺(jué)文中有錯(cuò)誤或者不清楚的地方,歡迎和我進(jìn)行討論~~