javascriptnode.jsnode.js-addonnode.js-nan

Checking instanceof in node.js addons using Nan


I am trying to verify that an object passed to a node addon is of the correct type before I unwrap it and start to use it. Here's the solution that I've cobbled together from looking at various sources on the web.

Persistent data:

Nan::Persistent<v8::Function> Event::constructor;
Nan::Persistent<v8::FunctionTemplate> Event::tpl;

The Init function:

void Event::Init(v8::Local<v8::Object> exports) {
    Nan::HandleScope scope;

    // Prepare constructor template
    v8::Local<v8::FunctionTemplate> ctor = Nan::New<v8::FunctionTemplate>(Event::New);
    ctor->InstanceTemplate()->SetInternalFieldCount(1);
    ctor->SetClassName(Nan::New("Event").ToLocalChecked());

    // create a template for checking instances
    Local<FunctionTemplate> localTemplate = Nan::New<FunctionTemplate>(Event::New);
    localTemplate->SetClassName(Nan::New("Event").ToLocalChecked());
    tpl.Reset(localTemplate);

    // Statics
    Nan::SetMethod(ctor, "x", Event::X);

    // Prototype
    Nan::SetPrototypeMethod(ctor, "addInfo", Event::addInfo);
    Nan::SetPrototypeMethod(ctor, "toString", Event::toString);

    constructor.Reset(ctor->GetFunction());
    Nan::Set(exports, Nan::New("Event").ToLocalChecked(), ctor->GetFunction());
}

And where I attempt to use it:

    if (Nan::New(tpl)->HasInstance(info[0])) {
        message = "it is an Event instance";
    }

The problem is that the HasInstance() never returns true.

The JavaScript code is basically

let e = new Event()
fn(e)     // where fn performs the HasInstance() test.

Solution

  • There is no need to make a second FunctionTemplate. The one you've set on the exports (ctor) is the one that gets used when you call new Event() in JS, while the second one (localTemplate) gets saved to Event::tpl and is the one from which the HasInstance() call gets made. They're different FunctionTemplates, so the HasInstance() call returns false.

    Instead of this:

    ...
    Local<FunctionTemplate> localTemplate = Nan::New<FunctionTemplate>(Event::New);
    localTemplate->SetClassName(Nan::New("Event").ToLocalChecked());
    tpl.Reset(localTemplate);
    ...
    

    just try this:

    ...
    tpl.Reset(ctor);
    ...