pmed / v8pp

Bind C++ functions and classes into V8 JavaScript engine
http://pmed.github.io/v8pp/
Other
898 stars 120 forks source link

console.log & util.inspect don't show native members #19

Closed nouknouk closed 8 years ago

nouknouk commented 8 years ago

Hi,

With Node 5.3, let's say I have a simple C++ class 'IScreen' with JS binding defined like that:

        v8pp::class_<IScreen> JS_IScreen(v8::Isolate::GetCurrent());
        JS_IScreen.set("init", &IScreen::init);
        JS_IScreen.set("inited", v8pp::property(&IScreen::isInited));
        JS_IScreen.set("shutdown", &IScreen::shutdown);

I have also a node module which references this class to let it be instaciable in JS code.

But when I try to 'dump' the object to the console of node, No 'native bound' fields are listed. This is the case when I'm using console.log(myObj) or even util.inspect(myObj, { showHidden:true }). On the contrary, iterating on the attributes of the object instance reveals the presence of the members:

var screen = new IScreen();
screen.customJsMember = 'sampleText';

console.log(require('util').inspect(screen, {showHidden:true}));
> { customJsMember: 'sampleText' }

for (var k in screen) console.log(k+"="+screen[k]);
> customJsMember=sampleText
> inited=true
> init=function init() { [native code] }
> shutdown=function shutdown() { [native code] }

I checked in v8pp code, but there's no presence of somehting like PropertyAttribute::DontEnum that I could remove to achieve a full display of all object members.

So here's my question: is there a simple way to output by default such 'native bound' members, as they are for other 'regular JS' members ?

Thanks in advance.

pmed commented 8 years ago

I found a similar question: http://stackoverflow.com/questions/27996250/how-to-make-nodejs-addon-show-property-info-like-a-regular-object

As it seems console.log() in Node.js enumerates only object's own properties. Properties and functions of wrapped C++ objects are set in prototype FunctionTemplate, so they can't be directly enumerated.

But you can expose toString function for you C++ class exposed to JavaScript and to use string conversion to dump the object like this:

JS_IScreen.set("toString", &IScreen::toString);
...
std::string IScreen::toString() const
{
    return "IScreen string representation";
}
console.log(screen + "")
// or
console.log("%s", screen)

Another Node.js specific way is to expose user-defined inspect function. You can return any V8 value from the custom inspect function. On C++ side this function should have 2 arguments: nodejs_inspect(int depth, v8::Local<v8::Object> options), where

JS_IScreen.set("inspect", &IScreen::nodejs_inspect);
...
v8::Local<v8::Value> IScreen::nodejs_inspect(v8::Isolate* isolate,
    int depth, v8::Local<v8::Object> options) const
{
    return v8pp::to_v8(isolate, "IScreen string representation");
    // or more sofisticated reprepsentation, like Object:
    //v8::Local<v8::Object> repr = v8::Object::New(isolate);
    //v8pp::set_option(isolate, repr, "inited", isInited);
    //return repr;
}

This way allows to print a wrapped object directly with console.log:

console.log(screen)