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?
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.