When using V8 as a scripting engine I expose a C++ function called construct_with_ec6_syntax
to Javascript. This function, when invoked, should simply return an instance of some_ec6_class
.
This C++ function should basically do the following equivalent Javascript:
return new some_ec6_class(111, 222);
This class will be defined in Javascript as follows with EC6 syntax:
class some_ec6_class
{
constructor(x, y) {
this.result = x + y;
}
}
My goal is to run the following in Javascript...
var the_instance = construct_with_ec6_syntax(111, 222);
the_instance.result ; // .. and get 333 here.
My current implementation for the C++ function is this:
void construct_with_ec6_syntax(const FunctionCallbackInfo<Value>& args) {
Handle<Object> global = args.GetIsolate()->GetCurrentContext()->Global();
std::string newvecfunc = "some_ec6_class";
Handle<Value> value = global->Get(String::NewFromUtf8(args.GetIsolate(), newvecfunc.c_str(), String::kNormalString, newvecfunc.length()));
Local<Value> result;
if (value->IsFunction()) {
Handle<Function> func = Handle<Function>::Cast(value);
Handle<Value> args2[2];
args2[0] = Number::New(args.GetIsolate(), 111);
args2[1] = Number::New(args.GetIsolate(), 222);
result = func->CallAsConstructor(args.GetIsolate()->GetCurrentContext(), 2, args2).ToLocalChecked();
}
args.GetReturnValue().Set(result);
}
Running this function from Javascript has it return undefined
! Instead of the object I expect. As xaxxon pointed out to me, it's because value->IsFunction()
returns false, but value->IsUndefined()
returns true. If I had defined the class using the with non EC6 syntax, the above function does return an instance..
function some_non_ec6_class(x, y) // this guy would work with the above function
{
this.result = x + y;
}
So I'm a bit confused! Do I somehow need to be more specific, like get the constructor
function from the object first, and then invoke CallAsConstructor
?
Any hint is appreciated!
(This question looks similar to Calling a v8 javascript function from c++ with an argument but is different.)
I'm using a V8 checkout from 22nd of October 2016. Complete testcase:
https://gist.github.com/rayburgemeestre/c0abd528f6f67edbfe686d484c45ddbb
Minor update:
As you can see in the comments, I also made a more specific test-case regarding "fetching" the class from the context here: https://gist.github.com/rayburgemeestre/df6193d532c7b7908fe27c89799bfa3a
Also I posted to the v8-users mailinglist: https://groups.google.com/forum/#!topic/v8-users/Hj2j4rJMwBw
class
is a way of creating a variable in javascript, similar tolet
. Variables created withclass
are block scoped and do not create global properties (again, similar tolet
). Therefor it is not available incontext.global
like a function is:http://exploringjs.com/es6/ch_variables.html
You would need to explicitly create a global variable for your code to work:
or explicitly pass in the class object to your c++ function after creating it with the 'traditional es6' syntax:
Edit: I've done some more digging and I believe that the context object has a LexicalEnvironment that is shared across its
script
s but is distinct from the global object. When a name is looked up, it traverses a parent hierarchy of LexicalEnvironments looking for the name. These lexical environments are not exposed via the API (and may not actually exist - they are a construct used by the JS specification to define behavior, not a required part of an implementation)