虽不能至,心向往之

—— 巴人也,操C++口音,混迹于京师,勉强度日……《史记·corelito列传》
posts - 8, comments - 15, trackbacks - 0, articles - 0

使用V8——Google Chrome 的 JavaScript 引擎(5)

Posted on 2008-10-23 10:45 sufan 阅读(3215) 评论(7)  编辑 收藏 引用 所属分类: 翻译
使用访问器访问 C++ 对象

为我们的类设置环境
怎样使用C++把一个类映射成为 JavaScript?首先来看看如下的例子: 
//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_; 
};

 
为了保证整个类映射后完全基于 JavaScript,我们对类的成员函数和变量都做映射。第一步,在上下文环境(context)中映射一个类模板:

Handle<FunctionTemplate> point_templ = FunctionTemplate::New();
point_templ
->SetClassName(String::New("Point"));


从字面上似乎看出:我们只是创建了一个“函数(function)”模板,但实际上它能够被看作一个类。它的名字是“Point”,我们将会在后面用到。
然后,通过访问原型(prototype) 类模板,我们能为这个类添加内建的方法:

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));


类能通过上面的代码“知道”它有两个方法。但这仍然是类的原型,我们必须要实例化这个类之后,才能使用这两个方法。

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


SetInternalFieldCount 函数为类指针申请空间(在后面会再一次提到)。一旦有了类的实例,我们就能为类中的变量添加访问器了:

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

至此,舞台算是搭好了,主角该上场了:
Point* p = new Point(00);

新类已经建好了,但只能在C++中访问。要对其进行访问,我们需要:
Handle<Function> point_ctor = point_templ->GetFunction();
Local
<Object> obj = point_ctor->NewInstance();
obj
->SetInternalField(0, External::New(p));


GetFunction 返回 point 的构造器,有了它,我们可以使用 NewInstance 函数来创建一个新的实例。然后,使用类指针来设置内部域(这个域的空间我们在前面已经使用 SetInternalFieldCount 函数申请好了)。这样一来,JavaScript 就能通过指针访问该对象。
有一点我们漏掉了,我们想从 JavaScript 中访问它,但只有类模板和实例,没有名字:

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


最后一步将“point”这个名字和 obj 实例联系起来。到这里,我们仅仅是完成了在脚本中使用“point”名字来创建 Point 类的过程。

在 JavaScript 中访问类方法
这里讲的并不是我们怎样在 Point 类中访问 Function_A……

先来看看回调函数 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_);
}


和普通的访问器类似,我们需对参数进行操作。而且,要能访问我们自己的类,还必须得从内部域中获取相关的类指针。在将内部域映射到“wrap”之后,就可以通过获取它的“值(Value)”来得到类指针,然后再进行类型转换。得到“point”类指针之后,可以通过它来调用 method_a ,method_a 来调用回调函数 PointMethod_A。

示例 v8_embedded_demo_with_object.zip  (Visual C++ Express 2008 )完整的包含了上述各个步骤。

最后,我非常希望这篇文章能对你有所帮助。如果感觉文中有错误或者不清楚的地方,欢迎和我进行讨论~~

Feedback

# re: 使用V8——Google Chrome 的 JavaScript 引擎(5)  回复  更多评论   

2008-10-25 16:56 by 金山词霸2008
真是一个好方法。

# re: 使用V8——Google Chrome 的 JavaScript 引擎(5)  回复  更多评论   

2009-04-27 15:44 by ccqcn
我怎么按照你这个,运行,没有任何效果啊。

# re: 使用V8——Google Chrome 的 JavaScript 引擎(5)  回复  更多评论   

2009-04-27 15:46 by ccqcn
请问,在js文件里,直接 var p=new Point() 构造C++里面的对象,怎么办呢??

# re: 使用V8——Google Chrome 的 JavaScript 引擎(5)  回复  更多评论   

2009-05-24 17:13 by pro.z
这篇文章对我很有帮助,首先感谢博主,我还有个问题想请问下,就是关于document.write这一类的怎么处理,V8自身好像没定义,我用你的方法映射的话,貌似返回值有问题,麻烦求助下您!

# re: 使用V8——Google Chrome 的 JavaScript 引擎(5)  回复  更多评论   

2009-06-24 17:57 by Heaven
如果我想实现 A.B.function();怎么做呢?请教下?

# re: 使用V8——Google Chrome 的 JavaScript 引擎(5)  回复  更多评论   

2011-09-09 09:21 by 有趣之极
好东西是好东西,但最新版本用vs2010编译不出来啊。。。

# re: 使用V8——Google Chrome 的 JavaScript 引擎(5)  回复  更多评论   

2011-11-03 13:19 by 门外汉
楼主翻译辛苦了

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理