2012-07-08 61 views
25

我正在使用C++和v8,並且遇到以下挑戰:我想能夠使用v8在javascript中定義函數,然後稍後通過調用函數C++。另外,我希望能夠將參數傳遞給C++的javascript函數。我認爲以下示例源代碼將最好地解釋它。檢查示例代碼的末尾,看看我正在嘗試完成什麼。從C++中調用v8 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); 

} 

任何提示?

UPDATE:

根據所給出的建議,我已經能夠總結了以下代碼。它已經過測試和工程:

#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; 

} 
+0

我假設IsInt32返回true,但Int32Value返回0? – 2012-07-10 19:36:32

+0

查看我的編輯 - 也許我們沒有傳遞足夠的參數... – 2012-07-10 19:52:37

+0

您的代碼中有一個錯誤:您在處理當前上下文後使用它。您必須在程序結束時放置處理線。 – banuj 2013-06-05 08:20:10

回答

13

我沒有測試過這一點,但它可能是像這樣將工作:

// ...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 
    } 
} 

編輯:

它看起來像你的JavaScript函數需要一個參數(由兩個值的數組組成),但它看起來像我們調用func通過傳遞在兩個論點。

爲了檢驗這一假設,你可以改變你的JavaScript函數取兩個參數並加以比較,如:

function test_function(test_arg1, test_arg2) { 
    var match = 0; 
    if (test_arg1 == test_arg2) { 
    match = 1; 
    } else { 
    match = 0; 
    } 
    return match; 
} 
+0

它似乎在工作。儘管如此,我仍然無法使用js_result。在編譯時如果(js_result.IsInt32)給出以下錯誤的部分:error:'class v8 :: Handle 'has no member named'Int32'| – user396404 2012-07-10 00:36:59

+1

@ user396404:也許試試'js_result-> IsInt32()'而不是? – 2012-07-10 11:26:38

+0

這確實奏效。代碼編譯完成,但即使值匹配,也不會返回值1:/ – user396404 2012-07-10 19:20:40

2

另一種更簡單的方法如下:

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); 

本質編譯一些代碼它返回一個匿名函數,然後用你想傳遞的任何參數調用它。

+0

v8 :: ScriptCompiler :: CompileFunctionInContext將「爲您的代碼封裝一個函數」位。 – xaxxon 2016-10-11 21:19:05