我是靠谱客的博主 包容茉莉,最近开发中收集的这篇文章主要介绍在V8引擎中包装C++类,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Javascript中不像C++有类的概念,其本质只是一个带有构造功能的函数,因此,关于C++类的注册主要是围绕着构造函数展开。
先给一个C++类MyObject,这是我们即将封装到Javascript中的类。

class MyObject {
public:
void doSomeThing();
static void JSRegister(Local<Object> exports);
private:
explicit MyObject() {}
~MyObject() {}
static void JSNew(const FunctionCallbackInfo<Value>& args);
static void JSDoSomeThing(const FunctionCallbackInfo<Value>& args);
};
void MyObject::doSomeThing() {
printf("%x %sn", this, __func__);
}

JSRegister接口的功能被设计为,将MyObject类的构造函数注入到参数exports所指向的javascript对象上。
doSomeThing则是成员函数,被调用时在终端上打印出this指针和函数名称。
JSNew和JSDoSomeThing是在向javascript注册类型过程中需要用到的回调函数。

首先看一下JSRegister的实现

void MyObject::JSRegister(Local<Object> exports) {
Isolate* isolate = exports->GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
//生成构造函数模版对象,并设置类名
Local<FunctionTemplate> function_t = FunctionTemplate::New(isolate, JSNew);
function_t->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked());
//生成构造函数对应的对象模版,并设置一个槽位用于存放与C++对象关联的指针数据
Local<ObjectTemplate> instance_t = function_t->InstanceTemplate();
instance_t->SetInternalFieldCount(1);
//在对应的javascript原型对象上设置doSomeThing方法
function_t->PrototypeTemplate()->Set(isolate, "doSomeThing", FunctionTemplate::New(isolate, MyObject::JSDoSomeThing));
//生成构造函数,并以MyObject属性名配置到exports指定的javascript对象上,注册过程完成
Local<Function> function = function_t->GetFunction(context).ToLocalChecked();
exports->Set(context, String::NewFromUtf8(isolate, "MyObject").ToLocalChecked(), function);
}

接下来再看JSNew回调函数的实现,如果javascript以构造方式调用了之前注册的MyObject方法——即new MyObject()——引擎将会回调这个JSNew函数,在JSNew函数里,我们要完成C++对象的创建,并将之与javascript中的对象进行关联。

void MyObject::JSNew(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
//如果javascript中的MyObject函数是以构造函数方式调用,就生成C++对象,否则返回NULL
if (args.IsConstructCall()) {
MyObject* obj = new MyObject();
//将javascript中生成的对象与C++对象指针关联
args.This()->SetAlignedPointerInInternalField(0, obj);
}
else
args.GetReturnValue().SetNull();
}

再看一下JSDoSomeThing回调的实现,这个回调将会在javascript中MyObject对象的doSomeThing方法被调用时执行。

void MyObject::JSDoSomeThing(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
//从javascript对象中取回对应的C++对象指针,并执行对应的成员函数。
MyObject* ptr = static_cast<MyObject*>(args.This()->GetAlignedPointerFromInternalField(0));
ptr->doSomeThing();
}

最后来一段测试程序

bool AppConfig::loadFile(std::string fileName)
{
ifstream infile;
infile.open("D:\projects\v8-test\test.js");
std::stringstream str_buffer_script;
str_buffer_script << infile.rdbuf();
string str_script(str_buffer_script.str());
infile.close();
V8::InitializeICUDefaultLocation(".");
V8::InitializeExternalStartupData(".");
std::unique_ptr<Platform> platform = platform::NewDefaultPlatform();
V8::InitializePlatform(platform.get());
V8::Initialize();
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = ArrayBuffer::Allocator::NewDefaultAllocator();
Isolate* isolate = Isolate::New(create_params);
{
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
Local<Context> context = Context::New(isolate, NULL);
Context::Scope context_scope(context);
Local<Object> global = context->Global();
//获取javascript的全局对象
MyObject::JSRegister(global);	//将MyObject类型注册到全局对象中
//在全局对象上额外注册一个log函数,方便输出对象信息
Local<FunctionTemplate> function_t = FunctionTemplate::New(isolate, Log);
Local<Function> function = function_t->GetFunction(context).ToLocalChecked();
global->Set(context, String::NewFromUtf8(isolate, "log").ToLocalChecked(), function);
Local<String> source = String::NewFromUtf8(isolate, str_script.c_str()).ToLocalChecked();
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
Local<Value> result = script->Run(context).ToLocalChecked();
}
isolate->Dispose();
V8::Dispose();
V8::ShutdownPlatform();
delete create_params.array_buffer_allocator;
return false;
}

一段测试用javascript代码

a = MyObject;
b = MyObject();
c = new MyObject();
d = c.__proto__;
e = new MyObject();
e.a = 1;
log("a = " + a);
log("b = " + b);
log("c = " + c);
log("d = " + d);
log("e = " + e);
log("c.a = " + c.a);
log("e.a = " + e.a);
log("doSomeThing in d = " + ('doSomeThing' in d));
log("doSomeThing in e.__proto__ = " + ('doSomeThing' in e.__proto__));
c.doSomeThing();
e.doSomeThing();

输出结果

a = function MyObject() { [native code] }
b = null
c = [object MyObject]
d = [object Object]
e = [object MyObject]
c.a = undefined
e.a = 1
doSomeThing in d = true
doSomeThing in e.__proto__ = true
81113710 doSomeThing
811139d0 doSomeThing

剩下的内容等待后续更新

最后

以上就是包容茉莉为你收集整理的在V8引擎中包装C++类的全部内容,希望文章能够帮你解决在V8引擎中包装C++类所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部