-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Symbol.hasInstance() for napi_instanceof on V8, when available #182
Comments
... though perhaps we shouldn't store it but rather retrieve it all the time, because it could be for a different context :/ This reduces the performance of |
Do we actually want that behavior? Does a native addon want its instanceof checks to be overridable? Does |
What do you mean by "its instanceof checks"? An addon may check whether anything is an instance of anything else. It need not necessarily restrict itself to checks of instances against constructors it provides itself. This is to be a generic API, right? As such, we should absolutely replicate precisely what the So, if the operator is now customizable via Additionally, in V8 using TBH, I was unaware of Of course, I say all this without having tested whether the function that is retrieved from the constructor's |
Does |
I'm checking that too. Even with plain JS though, only classses can be customized by way of |
Oh, actually, |
I don't understand -- a class in JS is just syntactic sugar for a constructor function with prototype properties. |
Here's the JS-only code I'm using for testing: class MyClass {
static [ Symbol.hasInstance ]( candidate ) {
return ( candidate.mark === "is an instance" );
}
}
var x = new MyClass();
var y = new MyClass();
console.log( x instanceof MyClass );
console.log( y instanceof MyClass );
y.mark = "is an instance";
console.log( x instanceof MyClass );
console.log( y instanceof MyClass );
console.log( typeof MyClass );
function MyFunction() {}
MyFunction[ Symbol.hasInstance ] = function( candidate ) {
return ( candidate.mark === "is an instance" );
}
var a = new MyFunction();
var b = new MyFunction();
console.log( a instanceof MyFunction );
console.log( b instanceof MyFunction ); |
For the plain-old-function I tried setting all of these as well: MyFunction.prototype[ Symbol.hasInstance ] = ...
MyFunction.constructor[ Symbol.hasInstance ] = ...
MyFunction.__proto__[Symbol.hasInstance ] = ... and |
It's static, so the equivalent would be: MyFunction[Symbol.hasInstance] = ... |
OK, so that was my original code. So, does the fact that it does not affect instanceof against plain-old-functions mean that there's a bug in V8 in that it does not conform to spec? |
Note that for our implementation of |
Take a look at this: http://node.green/#ES2015-built-ins-well-known-symbols-Symbol-hasInstance Here's the code they use for the test: function(){
var passed = false;
var obj = { foo: true };
var C = function(){};
Object.defineProperty(C, Symbol.hasInstance, {
value: function(inst) { passed = inst.foo; return false; }
});
obj instanceof C;
return passed;
} V8 passes the test on Node >= 6.10. |
Oh, |
Wow! OK, so if I use |
var hello = require( "bindings" )( "hello" );
var MyClass = hello.MyClass;
var hasInstance = hello.hasInstance;
var x = new MyClass();
var y = new MyClass();
console.log( "x: plain: native: " + ( x instanceof MyClass ) );
console.log( "x: plain: hasInstance: " + hasInstance( x ) );
console.log( "y: plain: native: " + ( y instanceof MyClass ) );
console.log( "y: plain: hasInstance: " + hasInstance( y ) );
console.log( "Setting constraint" );
Object.defineProperty( MyClass, Symbol.hasInstance, {
value: function( candidate ) {
return ( "mark" in candidate );
}
} );
console.log( "x: plain: native: " + ( x instanceof MyClass ) );
console.log( "x: plain: hasInstance: " + hasInstance( x ) );
console.log( "y: plain: native: " + ( y instanceof MyClass ) );
console.log( "y: plain: hasInstance: " + hasInstance( y ) );
console.log( "Satisfying constraint for x" );
x.mark = "abc";
console.log( "x: plain: native: " + ( x instanceof MyClass ) );
console.log( "x: plain: hasInstance: " + hasInstance( x ) );
console.log( "y: plain: native: " + ( y instanceof MyClass ) );
console.log( "y: plain: hasInstance: " + hasInstance( y ) ); and hello.cc: #include <nan.h>
using namespace v8;
static Nan::Persistent<FunctionTemplate> theTemplate;
NAN_METHOD(hasInstance) {
info.GetReturnValue().Set(Nan::New((theTemplate))->HasInstance(info[0]));
}
NAN_MODULE_INIT(Init) {
Local<FunctionTemplate> localTemplate = Nan::New<FunctionTemplate>();
localTemplate->SetClassName(Nan::New("MyClass").ToLocalChecked());
theTemplate.Reset(localTemplate);
Nan::Set(target, Nan::New("MyClass").ToLocalChecked(),
Nan::GetFunction(localTemplate).ToLocalChecked());
Nan::Set(target, Nan::New("hasInstance").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(hasInstance))
.ToLocalChecked());
}
NODE_MODULE(hello, Init) results in
|
So, since |
Agreed. We could still provide a separate |
Yeah, let's take the lazy (i.e. let someone file a bug requesting the feature) approach with |
This can be accomplished by retaining Symbol.hasInstance() in a static Persistent at the top of node_api.cc and then calling it. If the persistent is empty, we do what we do now. The persistent is initialized from
napi_module_register_cb()
.The text was updated successfully, but these errors were encountered: