如何使用JavaScriptCore将C ++对象传递给JavaScript函数

时间:2019-07-12 08:49:13

标签: javascript c++ javascriptcore

我已经在外部JavaScript文件sample.js中用JavaScript编写了一个函数。

function fileInfo(obj)
{
    /////
}

在sample.cpp文件中定义了一个类,如下所示:

class sample
{
   int i;
   ///
};

///

int main()
{
   sample obj;
   ///
   ///
}

如何将obj作为参数传递给JavaScript函数“ fileInfo”?

1 个答案:

答案 0 :(得分:0)

您不能将以一种编程语言编码的对象直接传递给以另一种编程语言编写的另一个程序。这是不可能的,因为对象的二进制布局从一种编程语言到另一种编程语言都不同。例如,在JavaScript中,数字类型为64位浮点数(8个字节)。如果您的C ++对象使用int32(4字节),则两个对象在内存中的布局都不同。为了兼容,两个对象至少应具有相同的大小(8个字节)(实际上比这要复杂得多)。总而言之,为了在不同的编程语言之间交换值,您需要以中立的格式达成一致或在数据类型之间进行转换。

用于C / CCP / Objective-C等的FFI(外部功能接口)JavaScript库,可以使C和JavaScript程序保持ABI兼容性。如果您需要混合C / CPP和JavaScript代码,则可以使用javascriptcoregtk库。

回到您的示例,您需要将Sample CPP对象转换为JSCValue对象以使其起作用。由于我在第一段中提到的原因,转换是不够的(程序员需要确定CPP对象及其在JavaScript中的等效对象之间的转换是什么样的)。这是一个可能的解决方案:

/**
 * Pass CPP object to JavaScript function
 * 
 * sample.js:
 * function fileInfo(obj)
 * {
 *  return "fileInfo: " + obj.i;
 * }
 * 
 * To compile: g++ main.cc -o main `pkg-config --cflags --libs javascriptcoregtk-4.0`
 *
 */

#include <iostream>
#include <string>
#include <fstream>
#include <streambuf>

#include <jsc/jsc.h>

using namespace std;

class Sample {
public:
    Sample(int i) { this->i = i; };
    JSCValue* toJSObject(JSCContext* jsContext);
    int i;
};

JSCValue* Sample::toJSObject(JSCContext* jsContext)
{
    JSCValue* ret = jsc_value_new_object(jsContext, nullptr, nullptr); 

    JSCValue* i = jsc_value_new_number(jsContext, this->i);
    jsc_value_object_define_property_data(ret, "i", JSC_VALUE_PROPERTY_ENUMERABLE, i);

    return ret;
}

int main(int argc, char* argv[])
{
    // Create jsContext.
    JSCContext* jsContext = jsc_context_new();

    // Load JavaScript file.
    const std::string filename = {"sample.js"};
    ifstream t("sample.js");
    string code((std::istreambuf_iterator<char>(t)),
            std::istreambuf_iterator<char>());
    JSCValue* ret = jsc_context_evaluate(jsContext, code.c_str(), static_cast<gssize>(code.length()));

    // Query 'fileInfo' and store it into JSCValue.
    JSCValue* fileInfo = jsc_context_evaluate(jsContext, "fileInfo", 8);
    if (!jsc_value_is_function(fileInfo)) {
        cerr << "Couldn't find function 'fileInfo'" << endl;
        exit(EXIT_FAILURE);
    }

    // Create CPP object.
    Sample obj(42);

    // Convert to JSCValue object and call 'fileInfo' function.
    ret = jsc_value_function_call(fileInfo, JSC_TYPE_VALUE, obj.toJSObject(jsContext), G_TYPE_NONE);
    cout << "ret: [" << jsc_value_to_string(ret) << "]" << endl;

    return 0;
}

注意:在上面的示例中,我没有释放内存以避免增加复杂性。

方法Sample::toJSObject将CPP对象转换为JSCValue对象。然后,函数调用jsc_value_function_call(fileInfo, JSC_TYPE_VALUE, obj.toJSObject(jsContext), G_TYPE_NONE);执行函数fileInfo(先前在此JavaScript上下文中加载),并传递CPP对象的“ cast”版本。执行该程序后的结果是:

ret: [fileInfo: 42]