Jack Jack - 1 year ago 130
C++ Question

V8 - Casting args.Data() back to void pointer

Currently I am binding a function using the following:

global->Set(String::NewFromUtf8(isolate, "print", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, V8Instance::js_print));

With the function:

static void js_print(const v8::FunctionCallbackInfo<v8::Value> &args);


void V8Instance::js_print(const v8::FunctionCallbackInfo<v8::Value> &args) {
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope(args.GetIsolate());
v8::String::Utf8Value str(args[i]);
std::cout << *str << std::endl;
std::cout << std::endl;

However I want my js_print function to have access to a variable which is a member of the class V8Instance. Does V8 have something like being able to use
boost::bind(&Class::function, this, ...)
that lets me bind member functions, or is there some way to pass the variable I need by reference/pointer to
every time it is called?


I have found out that I can pass a pointer to my class using the data parameter of

Local<External> self = External::New(isolate, (void *) this);
global->Set(String::NewFromUtf8(isolate, "print", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, V8Instance::js_print, self));

I can access this in my
function using
but this returns
object which I'm not sure how to cast back to
void *
and then back to my class pointer,
V8Instance *
. Does anyone know how to do this?

Answer Source

You may wrap a C++ object into a corresponding v8::ObjectTemplate and set accessors for it, as described in V8 Embedder's Guide.

To wrap a C++ class (i.e. to use many C++ instances of this C++ class from JavaScript) you will need to create V8 FunctionTemplate as a JS constructor function for the wrapped class which will store pointer to a C++ object in a V8 Object instance, and to set V8 function callbacks for desired member functions in the that class. These callbacks should unwrap C++ object from V8 object and to call appropriate member function for the unwrapped object.

This approach leads to writing a lot of boilerplate code. Node.js allows to inherit C++ class from node::ObjectWrap in a native addon.

I've also created v8pp library that binds C++ classes, functions, and lambdas in non-intrusive way, without inheritance.

There are several similar libraries exist. But, as I know, they are outdated and don't support new V8 versions.

Update. To get V8Instance* from external data you need to cast args.Data() value to v8::External and then get pointer from that external value and cast it to V8Instance*. Something like this:

void V8Instance::js_print(const v8::FunctionCallbackInfo<v8::Value> &args)
    v8::Local<v8::Extneral> ext = args.Data().As<v8::External>();
    V8Instance* self = static_cast<V8Instance*>(ext.Value());