简体   繁体   中英

v8 callback not working with JavaScript objects on the heap

I create an instance of a JavaScript object, like;

myObj1 = new myObject("Object1");

I then call a node.js c++ addon, which does a callback to the Javascript object...

myAddon = require('myAddon');
myAddon.greet(myObj1.name);

The c++ callback code looks like:

Local<Function> callback = Local<Function>::Cast(args[0]);
Isolate* isolate = args.GetIsolate();
const int argc = 1;
const char *parm = "Hello";
v8::Local<v8::Value> argv[argc] = {  v8::String::NewFromUtf8(isolate, parm) };
callback->Call(isolate->GetCurrentContext()->Global(), argc, argv);

But the problem is that the binding doesn't callback to the instance of the myObject, rather it appears to callback to the base JavaScript class. So there is no instance data.

From what I have been able to read over the past 2 days, the first parameter to the Call() method somehow becomes the "this" pointer in v8. So I would guess the problem might be that I am using a Global context

Does anyone have a clue how to correctly callback to a JavaScript object on the heap?

The this value is only set when you invoke a method in the form ab(...) or a[c](...) where a is any expression and b is an attribute name (or c is an expression evaluating as an attribute name) and the attribute value is a function.

That's a lot to unpack, but basically what it means is that when you do abc(d) then the function stored at abc is invoked with the value of the expression ab being bound to this in that function's context.

That is the only time this kind of magic happens.

So, when you invoke myAddon.greet(myObj1.name) , the function greet (fetched from the object myAddon ) is invoked with this being set to myAddon . There is no other magic happening. In particular, myObj1.name is evaluated, found to be a function, and this function object is passed as an argument. The detail that the function was obtained from myObj1 is not retained, which means that your C++ code as no mechanism it can use to obtain a reference to this object!

Instead, the proper way to do this in JavaScript is for the code passing the callback to bind this as it needs, using the bind() method of functions, like so:

myAddon.greet(myObj1.name.bind(myObj1));

Your C++ code will receive a proxy function object ( bind() creates a new function). This proxy will invoke the myObj1.name function with this being set to myObj1 , so your C++ code simply doesn't have to care about it.

To illustrate, the expression myObj1.name.bind(myObj1) is roughly equivalent to

(function (o, f) {
    return function () { return f.apply(o, arguments); };
}(myObj1, myObj1.name))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM