在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 %s\n", 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

剩下的内容等待后续更新

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值