Search code examples
c++v8

Call function from reference of C++ Object in JS (V8)


I have next JS code:

my_cpp_object.my_function(); // Works fine
var func = my_cpp_object.my_function;
func(); // Error, callback have not pointer to C++ object

This code should work fine in theory. But not in case the my_cpp_object is object which I create by v8::ObjectTemplate and v8::Context::Set(), because objects that I add to context by this way stores pointers to C++ object instance. And when I call my_cpp_object.my_function() it's call a callback function with const v8::FunctionCallbackInfo<v8::Value>& argument which have pointer to C++ object.

But when I call func() it's call a callback with const v8::FunctionCallbackInfo<v8::Value>& argument too, but there is no pointer to C++ object (args.Holder().As<v8::Object>()->InternalFieldCount() == 0)

Is it possible to resolve this problem?


Solution

  • This code should work fine in theory

    Unfortunately, no. In JavaScript, having a receiver matters for method calls. You can think of it as an implicit first argument. Assigning an object's method to a variable "loses" the receiver. In other words, the func variable does not remember that it was loaded from my_cpp_object, so the func() call has no way of passing a pointer to this object along with the call. Consider this pure-JavaScript example:

    var o = {
        x: 42, 
        get: function() { return this.x; }
    }
    o.get();  // 42
    var func = o.get;
    func();  // undefined
    

    (The reason you get undefined is because in the func() call, the global object will implicitly be the receiver, so the .x load will load a non-existing property from that, so you get undefined.)

    In short, if your C++-defined method relies on args.Holder or args.Receiver for anything (or if your JavaScript-defined method relies on this in any way), then the call must have the right receiver.

    Any solution to this must happen on the JavaScript side. If you need a way to store only a single function, you can create a closure to capture the receiver:

    var func = function() { return my_cpp_object.my_function(); }
    func();  // Works fine.