如何使用JavaScriptCore将C ++对象传递给JavaScript函数
我已经在外部JavaScript文件sample.js中用JavaScript编写了一个函数.
I've written a function in JavaScript in an external JavaScript file sample.js .
function fileInfo(obj)
{
/////
}
我在sample.cpp文件中定义了一个类,如下所示:
I have a class defined in the sample.cpp file as follows :
class sample
{
int i;
///
};
///
int main()
{
sample obj;
///
///
}
如何将obj作为参数传递给JavaScript函数"fileInfo"?
How can we pass obj to the JavaScript function "fileInfo" as a parameter?
您不能将以一种编程语言编码的对象直接传递给以另一种编程语言编写的另一个程序.这是不可能的,因为对象的二进制布局从一种编程语言到另一种编程语言都不同.例如,在JavaScript中,数字类型为64位浮点数(8个字节).如果您的C ++对象使用int32(4个字节),则两个对象在内存中的布局都不同.为了兼容,两个对象至少应具有相同的大小(8个字节)(实际上比这要复杂得多).总而言之,为了在不同的编程语言之间交换值,您需要以中性的格式达成一致,或者在数据类型之间进行转换.
You cannot directly pass an object encoded in one programming language to another program written in a different programming language. This is not possible since the binary layout of objects differ from one programming language to another. For instance, in JavaScript the Number type is a 64-bit float (8 bytes). If your C++ object uses an int32 (4 bytes), then the layout of both objects in memory differ. Both objects should have the same size (8 bytes), at least, to be compatible (actually it gets much more complicated than that). In summary, in order to exchange values between different programming languages you need either to agree in a neutral format or to convert between data types.
用于C/CCP/Objective-C等的FFI(外部功能接口)JavaScript库,可以使C和JavaScript程序保持ABI兼容性.如果需要混合C/CPP和JavaScript代码,则可以使用javascriptcoregtk
库.
The FFI (Foreign Function Interface) JavaScript libraries for C/CCP/Objective-C, etc allows you to keep ABI compatibility between C and JavaScript programs. If you need to mingle C/CPP and JavaScript code you can use the javascriptcoregtk
library.
回到您的示例,您需要将Sample
CPP对象转换为JSCValue
对象,以使其正常工作.由于我在第一段中提到的原因,强制转换是不够的(程序员需要确定CPP对象及其在JavaScript中的等效对象之间的转换是什么样的).这是一个可能的解决方案:
Going back to your example, you will need to convert your Sample
CPP object to a JSCValue
object to make it work. A casting is not enough, for the reasons I commented in the first paragraph (the programmer needs to decide how the conversion between the CPP object and its equivalent in JavaScript should look like). Here is a possible solution:
/**
* 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;
}
注意:在上面的示例中,我没有释放内存以避免增加复杂性.
NOTE: I didn't free memory in the example above to avoid adding complexity.
方法Sample::toJSObject
将CPP对象转换为JSCValue对象.然后,函数调用jsc_value_function_call(fileInfo, JSC_TYPE_VALUE, obj.toJSObject(jsContext), G_TYPE_NONE);
执行函数fileInfo
(先前在此JavaScript上下文中加载),并传递CPP对象的"cast"版本.执行该程序后的结果是:
The method Sample::toJSObject
casts your CPP object to a JSCValue object. Then the function call jsc_value_function_call(fileInfo, JSC_TYPE_VALUE, obj.toJSObject(jsContext), G_TYPE_NONE);
executes function fileInfo
(previously loaded in this JavaScript context) and passes a "cast" version of the CPP object. The result after executing this program is:
ret: [fileInfo: 42]