我目前正在尝试获取我在JS中调用的函数的返回值。以下代码可以重现(减去v8)
#include "v8.h"
#include "libplatform/libplatform.h"
#include <string>
#include <cassert>
int64_t repro()
{
auto isolate = v8::Isolate::New(initializer.create_params_);
assert(isolate != nullptr);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
auto context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
assert(context.IsEmpty() == false);
auto global = context->Global();
std::string script = "function foo() {\n"
" return BigInt(1);\n"
"}";
v8::Local<v8::String> sourceScript =
v8::String::NewFromUtf8(isolate, script.c_str(),
v8::NewStringType::kNormal)
.ToLocalChecked();
v8::Local<v8::Script> s =
v8::Script::Compile(context, sourceScript).ToLocalChecked();
s->Run(context);
v8::Local<v8::String> name =
v8::String::NewFromUtf8(isolate, "foo",
v8::NewStringType::kInternalized)
.ToLocalChecked();
auto value = global->Get(context, name).ToLocalChecked();
assert(value->IsFunction());
auto func = v8::Handle<v8::Function>::Cast(value);
auto result = func->Call(context, context->Global(), 0, nullptr)
.ToLocalChecked();
assert(result->IsBigInt());
auto bigint = result->IntegerValue(context);
assert(bigint.IsNothing() == false);
return bigint.ToChecked();
}
当我现在查看bigint时-类型报告为BigInt,但是IsNothing()返回true。我在做什么错了?
谢谢
Tobias
答案 0 :(得分:2)
如文档所述,v8::Value::IntegerValue()
“返回等效的ToInteger()->Value()
”,这意味着在Nothing
上调用它会引发异常(即返回BigInt
),反映出以下事实:在JavaScript中,在BigInt
上调用“抽象操作” ToInteger()
会抛出TypeError
,或者换句话说:BigInt
并不只是隐式转换到Number
。
要从C ++中提取BigInt
的值,可以执行以下操作:
int64_t bigint = v8::Local<v8::BigInt>::cast(result)->Int64Value();
当然,当BigInt的值大于int64时,将给出错误的结果。它需要一个可选的bool*
来指示到int64的转换是无损的还是被截断的。如果需要更大的值,可以使用ToWordsArray(...)
方法。
如何从V8获取JS函数的返回值?
与您完全一样:
v8::MaybeLocal<v8::Value> result = func->Call(...);
请注意,使用.ToLocalChecked();
是有风险的:如果函数引发异常而不返回值,则.ToLocalChecked()
将崩溃。如果您不控制该函数的代码,因此不能保证不会抛出该函数,则最好测试结果是否为空,并妥善处理异常。有关大量示例和其他说明,请参见V8的samples/
目录或v8.dev/docs/上的文档。
(旁注:我建议减少使用auto
。这有助于查看类型。例如v8::Value
,v8::Local<v8::Value>
,v8::MaybeLocal<v8::Value>
之间的区别,和v8::Local<v8::BigInt>
是有意义的,当您不只是将它们隐藏在auto
后面时,它可以帮助您编写正确的代码。