问题
I've written a function in JavaScript in an external JavaScript file sample.js .
function fileInfo(obj)
{
/////
}
I have a class defined in the sample.cpp file as follows :
class sample
{
int i;
///
};
///
int main()
{
sample obj;
///
///
}
How can we pass obj to the JavaScript function "fileInfo" as a parameter?
回答1:
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.
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.
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.
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]
来源:https://stackoverflow.com/questions/57003419/how-to-pass-c-object-to-javascript-function-using-javascriptcore