instanceof.

162 views
Skip to first unread message

Jane Chen

unread,
Jun 26, 2014, 12:48:36 PM6/26/14
to v8-u...@googlegroups.com
I have an object instantiated from a template, which has a class name set.  When I do instanceof on it in JavaScript, it only shows it's an object, but not of my class.  My class seems unknown.  Does v8 provide a callback API for instanceof?  Or object is the best you can get?

Ben Noordhuis

unread,
Jun 27, 2014, 12:12:09 AM6/27/14
to v8-u...@googlegroups.com
You mean `(new YourClass instanceof YourClass) === false`? What does
`Object.prototype.toString.call(new YourClass)` print?

Andreas Rossberg

unread,
Jun 27, 2014, 2:47:11 AM6/27/14
to v8-u...@googlegroups.com
If I understand your problem correctly then this is working as
intended. JavaScript has no notion of class, and the semantics of
instanceof in JavaScript does not care about class names. The only
relevance of the so-called class name that you can set through the API
is for the result of toString.

/Andreas

Jane Chen

unread,
Jun 27, 2014, 3:29:37 PM6/27/14
to v8-u...@googlegroups.com
Ben,

Say if my class is called ValueIterator, and "it" is an instance of it, if I do:

> Object.prototype.toString.call(it);
[object ValueIterator]
> it instanceof ValueIterator;
(shell):1: ReferenceError: ValueIterator is not defined
it instanceof ValueIterator;
              ^
ReferenceError: ValueIterator is not defined
    at (shell):1:15

Ben Noordhuis

unread,
Jun 27, 2014, 6:22:14 PM6/27/14
to v8-u...@googlegroups.com
On Fri, Jun 27, 2014 at 9:29 PM, Jane Chen <jxch...@gmail.com> wrote:
> Ben,
>
> Say if my class is called ValueIterator, and "it" is an instance of it, if I
> do:
>
>> Object.prototype.toString.call(it);
> [object ValueIterator]
>> it instanceof ValueIterator;
> (shell):1: ReferenceError: ValueIterator is not defined
> it instanceof ValueIterator;
> ^
> ReferenceError: ValueIterator is not defined
> at (shell):1:15

The error message suggests that you called
FunctionTemplate::SetClassName() but haven't exposed the class on the
global object.

Jane Chen

unread,
Jul 9, 2014, 3:01:50 PM7/9/14
to v8-u...@googlegroups.com
Ben,

How am I supposed to expose the class to the global object?

I have this:

// create and bind XMLBuilder function
v8::Local<v8::FunctionTemplate> bldrTemp =
v8::FunctionTemplate::New(isolate,createBuilder);
v8::Local<v8::String> bldrLabel =
v8::String::NewFromUtf8(isolate, "XMLBuilder");
bldrTemp->SetClassName(bldrLabel);
global->Set(bldrLabel,bldrTemp);

> var b = new XMLBuilder();
> b instanceof XMLBuilder;
false
> Object.prototype.toString.call(b);
[object XMLBuilder]

Ben Noordhuis

unread,
Jul 9, 2014, 3:52:39 PM7/9/14
to v8-u...@googlegroups.com
On Wed, Jul 9, 2014 at 9:01 PM, Jane Chen <jxch...@gmail.com> wrote:
> Ben,
>
> How am I supposed to expose the class to the global object?
>
> I have this:
>
> // create and bind XMLBuilder function
> v8::Local<v8::FunctionTemplate> bldrTemp =
> v8::FunctionTemplate::New(isolate,createBuilder);
> v8::Local<v8::String> bldrLabel =
> v8::String::NewFromUtf8(isolate, "XMLBuilder");
> bldrTemp->SetClassName(bldrLabel);
> global->Set(bldrLabel,bldrTemp);
>
>> var b = new XMLBuilder();
>> b instanceof XMLBuilder;
> false
>> Object.prototype.toString.call(b);
> [object XMLBuilder]

In pseudo-code:

Local<Context> context = /* ... */;
Local<String> name = /* ... */;
Local<FunctionTemplate> t = FunctionTemplate::New(...);
t->SetClassName(name);
context->Global()->Set(name, t->GetFunction());

Note that you don't need to expose the constructor on the actual
global object, as long as it's in scope when you call `instanceof`.
HTH.

Jane Chen

unread,
Oct 7, 2014, 6:59:37 PM10/7/14
to v8-u...@googlegroups.com
Picking up this thread again:

I have no problem exposing the class to the global context uisng the pattern shown above.  My problem is that the returned value of the class constructor is not an instanceof that class if I construct object in it to return:

static void
foo(const v8::FunctionCallbackInfo<v8::Value>& args)
{
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope handle_scope(isolate);
  v8::Local<v8::ObjectTemplate> result = v8::ObjectTemplate::New(isolate);
  result->Set(v8::String::NewFromUtf8(isolate, "print"),
    v8::FunctionTemplate::New(isolate, Print));
  result->SetInternalFieldCount(1);
  v8::Local<v8::Object> builder = result->NewInstance();
  builder->SetAlignedPointerInInternalField(0,0);
  return args.GetReturnValue().Set(builder);
}

v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(isolate, foo);
result->SetClassName(v8::String::NewFromUtf8(isolate,"Foo"));
global->Set(v8::String::NewFromUtf8(isolate, "Foo"),result);

> var x = new Foo();
> x instanceof Foo;
false

Is there any API that allows me to construct a wrapped object in foo() that is an instanceof Foo?

Thanks!

Ben Noordhuis

unread,
Oct 8, 2014, 7:30:50 AM10/8/14
to v8-u...@googlegroups.com
I think you have a small bug in your example code. In the call to
global->Set(), the value should be result->GetFunction().

In no particular order:

- Assign prototype methods with result->PrototypeTemplate()->Set(...),
don't instantiate a new ObjectTemplate.

- args.IsConstructCall() should return true in the constructor function.

- Operate on args.This(), calling args.GetReturnValue().Set() has no effect.

Hope that helps!

Jane Chen

unread,
Oct 8, 2014, 4:02:18 PM10/8/14
to v8-u...@googlegroups.com
Ben,

I was able to get instanceof returning true following your tips.  Thanks.  But it seems to me this design assumes that there is only a singleton Function we are operating on as I'm always interacting with This, which is the function returned from FunctionTemplate.GetFunction(). 

If I want to dynamically create embedded objects from FunctionTemplates, is there a way to keep them "instanceof" of a certain class?

Jane

Ben Noordhuis

unread,
Oct 8, 2014, 5:26:02 PM10/8/14
to v8-u...@googlegroups.com
`o instanceof F` is more or less equivalent to recursively checking if
`o.__proto__.constructor === F`. That is, you can make objects pass
the instanceof test by making their constructors inherit from one
another. For example:

function A() {}
function B() {}
B.prototype = Object.create(A.prototype);
(new B) instanceof A; // true

You can accomplish the same thing with the C++ API in a number of
ways. In your case, just FunctionTemplate::Inherit() might be enough.

Jane Chen

unread,
Oct 10, 2014, 5:14:36 PM10/10/14
to v8-u...@googlegroups.com
One more try:

In my constructor function foo:


static void
foo(const v8::FunctionCallbackInfo<v8::Value>& args)
{
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope handleScope(isolate);
  args.GetReturnValue().Set(
    v8::Local<v8::Function>::Cast(args.This())->New(isolate,bar));
}

> var f = new Foo();
> f instanceof Foo;
false

Now if I change New to NewInstance, I get a crash from V8.  I don't see why an instance new'ed from the function still isn't "instanceof" the function.

Jane

Ben Noordhuis

unread,
Oct 11, 2014, 7:01:23 AM10/11/14
to v8-u...@googlegroups.com
On Fri, Oct 10, 2014 at 11:14 PM, Jane Chen <jxch...@gmail.com> wrote:
> One more try:
>
> In my constructor function foo:
>
> static void
> foo(const v8::FunctionCallbackInfo<v8::Value>& args)
> {
> v8::Isolate* isolate = args.GetIsolate();
> v8::HandleScope handleScope(isolate);
> args.GetReturnValue().Set(
> v8::Local<v8::Function>::Cast(args.This())->New(isolate,bar));
> }
>
>> var f = new Foo();
>> f instanceof Foo;
> false
>
> Now if I change New to NewInstance, I get a crash from V8. I don't see why
> an instance new'ed from the function still isn't "instanceof" the function.

Jane, I'm not sure what you expect that to do but .This() is an
object, not a function. You _can_ override the return value but I
don't think you're really supposed to.

Jane Chen

unread,
Oct 14, 2014, 1:20:02 AM10/14/14
to v8-u...@googlegroups.com
If I don't set return value, and only operate on This, how do I associate a different C++ object to the newly constructed JS object? 

The reason that I kept trying to return something other than This was because I need to dynamically create objects backed by different C++ objects each time the constructor's callback is called.  Even when I create a new function template inheriting the original, and set the return value to be the inheriting template's function, instanecof still returns false:

  v8::Local<v8::FunctionTemplate> subTemp =
      v8::FunctionTemplate::New(isolate,createBuilder,builder);
  subTemp->Inherit(builderTemp);

  return args.GetReturnValue().Set(subTemp->GetFunction());

Ben Noordhuis

unread,
Oct 14, 2014, 9:03:30 AM10/14/14
to v8-u...@googlegroups.com
On Tue, Oct 14, 2014 at 7:20 AM, Jane Chen <jxch...@gmail.com> wrote:
> If I don't set return value, and only operate on This, how do I associate a
> different C++ object to the newly constructed JS object?

You store the pointer to the C++ object in an InternalField slot on
the .This() object.

Make sure to reserve a slot with
function_template->InstanceTemplate()->SetInternalFieldCount(1), where
function_template is the FunctionTemplate of your constructor
function.

Jane Chen

unread,
Oct 14, 2014, 11:02:07 AM10/14/14
to v8-u...@googlegroups.com
Yes, that works.  But every time the callback function is called, This() object is the same one.

Jane Chen

unread,
Oct 14, 2014, 2:39:18 PM10/14/14
to v8-u...@googlegroups.com
Please ignore my last post.  Things are working for me now. 

Thanks a lot for your support Ben! 

Jane
Reply all
Reply to author
Forward
0 new messages