使用参数从 C++ 调用 v8 javascript 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11387015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling a v8 javascript function from c++ with an argument
提问by user396404
I am working with c++ and v8, and have run into the following challenge: I want to be able to define a function in javascript using v8, then call the function later on through c++. Additionally, I want to be able to pass an argument to the javascript function from c++. I think the following sample source code would explain it best. Check towards the end of the sample code to see what I am trying to accomplish.
我正在使用 c++ 和 v8,并且遇到了以下挑战:我希望能够使用 v8 在 javascript 中定义一个函数,然后稍后通过 c++ 调用该函数。此外,我希望能够将参数从 C++ 传递给 javascript 函数。我认为以下示例源代码可以最好地解释它。检查示例代码的末尾以了解我要完成的任务。
#include <v8.h>
#include <iostream>
#include <string>
#include <array>
using namespace v8;
int main(int argc, char* argv[]) {
// Create a stack-allocated handle scope.
HandleScope handle_scope;
// Create a new context.
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
Handle<String> source;
Handle<Script> script;
Handle<Value> result;
// Create a string containing the JavaScript source code.
source = String::New("function test_function(test_arg) { var match = 0;if(test_arg[0] == test_arg[1]) { match = 1; }");
// Compile the source code.
script = Script::Compile(source);
// What I want to be able to do (this part isn't valid code..
// it just represents what I would like to do.
// An array is defined in c++ called pass_arg,
// then passed to the javascript function test_function() as an argument
std::array< std::string, 2 > pass_arg = {"value1", "value2"};
int result = script->callFunction("test_function", pass_arg);
}
Any tips?
有小费吗?
UPDATE:
更新:
Based on the advice given, I have been able to put together the following code. It has been tested and works:
根据给出的建议,我已经能够将以下代码放在一起。它已经过测试并且可以正常工作:
#include <v8.h>
#include <iostream>
#include <string>
using namespace v8;
int main(int argc, char* argv[]) {
// Create a stack-allocated handle scope.
HandleScope handle_scope;
// Create a new context.
Persistent<Context> context = Context::New();
//context->AllowCodeGenerationFromStrings(true);
// Enter the created context for compiling and
// running the hello world script.
Context::Scope context_scope(context);
Handle<String> source;
Handle<Script> script;
Handle<Value> result;
// Create a string containing the JavaScript source code.
source = String::New("function test_function() { var match = 0;if(arguments[0] == arguments[1]) { match = 1; } return match; }");
// Compile the source code.
script = Script::Compile(source);
// Run the script to get the result.
result = script->Run();
// Dispose the persistent context.
context.Dispose();
// Convert the result to an ASCII string and print it.
//String::AsciiValue ascii(result);
//printf("%s\n", *ascii);
Handle<v8::Object> global = context->Global();
Handle<v8::Value> value = global->Get(String::New("test_function"));
Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
Handle<Value> args[2];
Handle<Value> js_result;
int final_result;
args[0] = v8::String::New("1");
args[1] = v8::String::New("1");
js_result = func->Call(global, 2, args);
String::AsciiValue ascii(js_result);
final_result = atoi(*ascii);
if(final_result == 1) {
std::cout << "Matched\n";
} else {
std::cout << "NOT Matched\n";
}
return 0;
}
采纳答案by Nate Kohl
I haven't tested this, but it's possible that something like this will work:
我还没有测试过这个,但是这样的事情可能会起作用:
// ...define and compile "test_function"
Handle<v8::Object> global = context->Global();
Handle<v8::Value> value = global->Get(String::New("test_function"));
if (value->IsFunction()) {
Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
Handle<Value> args[2];
args[0] = v8::String::New("value1");
args[1] = v8::String::New("value2");
Handle<Value> js_result = func->Call(global, 2, args);
if (js_result->IsInt32()) {
int32_t result = js_result->ToInt32().Value();
// do something with the result
}
}
Edit:
编辑:
It looks like your javascript function expects a single argument (consisting of an array of two values), but it kinda looks like we're calling func
by passing in two arguments.
看起来您的 javascript 函数需要一个参数(由两个值组成的数组),但看起来我们是func
通过传入两个参数来调用的。
To test this hypothesis, you could change your javascript function to take two arguments and compare them, e.g.:
为了测试这个假设,你可以改变你的 javascript 函数来接受两个参数并比较它们,例如:
function test_function(test_arg1, test_arg2) {
var match = 0;
if (test_arg1 == test_arg2) {
match = 1;
} else {
match = 0;
}
return match;
}
回答by alijandro
For new version of v8, you can use v8::Object::CallAsFunction
or v8::Function::Call
to call a javascript function. Here is an example for recent version (7.4.x)
对于新版本的 v8,您可以使用v8::Object::CallAsFunction
或v8::Function::Call
调用javascript 函数。这是最近版本 (7.4.x) 的示例
#include <iostream>
#include <libplatform/libplatform.h>
#include <v8.h>
int main(int argc, char* argv[])
{
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
v8::Isolate::CreateParams createParams;
createParams.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(createParams);
std::cout << v8::V8::GetVersion() << std::endl;
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, "var foo=function(){return 'foo get called';}");
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8::TryCatch tryCatch(isolate);
v8::MaybeLocal<v8::Value> result = script->Run(context);
if (result.IsEmpty()) {
v8::String::Utf8Value e(isolate, tryCatch.Exception());
std::cerr << "Exception: " << *e << std::endl;
} else {
v8::String::Utf8Value r(isolate, result.ToLocalChecked());
std::cout << *r << std::endl;
}
v8::Local<v8::Value> foo_value = context->Global()->Get(v8::String::NewFromUtf8(isolate, "foo"));
if (foo_value->IsFunction()) {
v8::Local<v8::Value> foo_ret = foo_value->ToObject(isolate)->CallAsFunction(context, context->Global(), 0, nullptr).ToLocalChecked();
v8::String::Utf8Value utf8Value(isolate, foo_ret);
std::cout << "CallAsFunction result: " << *utf8Value << std::endl;
v8::Local<v8::Object> foo_object = foo_value->ToObject(isolate);
v8::Local<v8::Value> foo_result = v8::Function::Cast(*foo_object)->Call(context, context->Global(), 0, nullptr).ToLocalChecked();
std::cout << "Call result: " << *(v8::String::Utf8Value(isolate, foo_result)) << std::endl;
} else {
std::cerr << "foo is not a function" << std::endl;
}
}
isolate->Dispose();
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete createParams.array_buffer_allocator;
return EXIT_SUCCESS;
}
回答by jkp
Another simpler method is as follows:
另一种更简单的方法如下:
Handle<String> code = String::New(
"(function(arg) {\n\
console.log(arg);\n\
})");
Handle<Value> result = Script::Compile(code)->Run();
Handle<Function> function = Handle<Function>::Cast(result);
Local<Value> args[] = { String::New("testing!") };
func->Call(Context::GetCurrent()->Global(), 1, args);
Essentially compile some code that returns an anonymous function, then call that with whatever arguments you want to pass.
基本上编译一些返回匿名函数的代码,然后使用您想要传递的任何参数调用它。