如何从 C++ 中 return 一个新的 V8 javascript "class" 实例?
How to return a new V8 javascript "class" instance from within C++?
当使用 V8 作为脚本引擎时,我将一个名为 construct_with_ec6_syntax
的 C++ 函数公开给 Javascript。此函数在调用时应该只是 return some_ec6_class
.
的一个实例
此 C++ 函数基本上应该执行以下等效操作 Javascript:
return new some_ec6_class(111, 222);
这个 class 将在 Javascript 中定义如下 with EC6 语法:
class some_ec6_class
{
constructor(x, y) {
this.result = x + y;
}
}
我的目标是 运行 以下 Javascript...
var the_instance = construct_with_ec6_syntax(111, 222);
the_instance.result ; // .. and get 333 here.
我当前的 C++ 函数实现是这样的:
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);
}
运行Javascript的这个函数有returnundefined
!而不是我期望的对象。正如 xaxxon 向我指出的那样,这是因为 value->IsFunction()
return 是错误的,但是 value->IsUndefined()
return 是正确的。如果我使用 with non EC6 语法定义了 class,上面的函数 does return 一个实例..
function some_non_ec6_class(x, y) // this guy would work with the above function
{
this.result = x + y;
}
所以我有点困惑!我是否需要更具体一些,比如首先从对象中获取 constructor
函数,然后调用 CallAsConstructor
?
感谢任何提示!
(这个问题看起来类似于
Calling a v8 javascript function from c++ with an argument 但不同。)
我使用的是 2016 年 10 月 22 日的 V8 结帐。
完整的测试用例:
https://gist.github.com/rayburgemeestre/c0abd528f6f67edbfe686d484c45ddbb
次要更新:
正如您在评论中看到的那样,我还根据此处的上下文针对 "fetching" 和 class 做了一个更具体的测试用例:https://gist.github.com/rayburgemeestre/df6193d532c7b7908fe27c89799bfa3a
我也发布到 v8-users 邮件列表:https://groups.google.com/forum/#!topic/v8-users/Hj2j4rJMwBw
class
是在javascript中创建变量的一种方式,类似于let
。使用 class
创建的变量是块范围的并且不创建全局属性(同样,类似于 let
)。因此它在 context.global
中不可用,就像函数是:
http://exploringjs.com/es6/ch_variables.html
function Complete Block Yes
class No Block No
您需要显式创建全局变量才能让您的代码正常工作:
some_es6_class = class{};
或在使用 'traditional es6' 语法创建 class 对象后显式将其传递给您的 C++ 函数:
class some_es6_class{};
some_native_function(some_es6_class);
编辑:我做了更多的挖掘,我 相信 上下文对象有一个 LexicalEnvironment,它在其 script
中共享,但与全局对象。查找名称时,它会遍历 LexicalEnvironments 的父层次结构以查找该名称。这些词法环境不会通过 API 公开(并且可能实际上不存在 - 它们是 JS 规范用来定义行为的构造,而不是实现的必需部分)
当使用 V8 作为脚本引擎时,我将一个名为 construct_with_ec6_syntax
的 C++ 函数公开给 Javascript。此函数在调用时应该只是 return some_ec6_class
.
此 C++ 函数基本上应该执行以下等效操作 Javascript:
return new some_ec6_class(111, 222);
这个 class 将在 Javascript 中定义如下 with EC6 语法:
class some_ec6_class
{
constructor(x, y) {
this.result = x + y;
}
}
我的目标是 运行 以下 Javascript...
var the_instance = construct_with_ec6_syntax(111, 222);
the_instance.result ; // .. and get 333 here.
我当前的 C++ 函数实现是这样的:
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);
}
运行Javascript的这个函数有returnundefined
!而不是我期望的对象。正如 xaxxon 向我指出的那样,这是因为 value->IsFunction()
return 是错误的,但是 value->IsUndefined()
return 是正确的。如果我使用 with non EC6 语法定义了 class,上面的函数 does return 一个实例..
function some_non_ec6_class(x, y) // this guy would work with the above function
{
this.result = x + y;
}
所以我有点困惑!我是否需要更具体一些,比如首先从对象中获取 constructor
函数,然后调用 CallAsConstructor
?
感谢任何提示!
(这个问题看起来类似于 Calling a v8 javascript function from c++ with an argument 但不同。)
我使用的是 2016 年 10 月 22 日的 V8 结帐。 完整的测试用例:
https://gist.github.com/rayburgemeestre/c0abd528f6f67edbfe686d484c45ddbb
次要更新:
正如您在评论中看到的那样,我还根据此处的上下文针对 "fetching" 和 class 做了一个更具体的测试用例:https://gist.github.com/rayburgemeestre/df6193d532c7b7908fe27c89799bfa3a
我也发布到 v8-users 邮件列表:https://groups.google.com/forum/#!topic/v8-users/Hj2j4rJMwBw
class
是在javascript中创建变量的一种方式,类似于let
。使用 class
创建的变量是块范围的并且不创建全局属性(同样,类似于 let
)。因此它在 context.global
中不可用,就像函数是:
http://exploringjs.com/es6/ch_variables.html
function Complete Block Yes
class No Block No
您需要显式创建全局变量才能让您的代码正常工作:
some_es6_class = class{};
或在使用 'traditional es6' 语法创建 class 对象后显式将其传递给您的 C++ 函数:
class some_es6_class{};
some_native_function(some_es6_class);
编辑:我做了更多的挖掘,我 相信 上下文对象有一个 LexicalEnvironment,它在其 script
中共享,但与全局对象。查找名称时,它会遍历 LexicalEnvironments 的父层次结构以查找该名称。这些词法环境不会通过 API 公开(并且可能实际上不存在 - 它们是 JS 规范用来定义行为的构造,而不是实现的必需部分)