将任意 Javascript 数据对象传递给 Node.js C++ 插件
Pass arbitrary Javascript data object to Node.js C++ addon
我有一个使用 Nan 用 C++ 编写的 Node.js 插件。非常好用。但是,我无法弄清楚如何让我的节点 Javascript 代码将任意数据对象(例如 {attr1:42, attr2:'hi', attr3:[5,4,3,2,1]}
)传递给 C++ 插件。
到目前为止,我已经通过在我的数据对象上调用 JSON.stringify()
然后在 C++ 端解析字符串化 JSON 来解决这个问题。
理想情况下,我想避免复制数据而只是获取对我可以访问的数据对象的引用,或者至少在本机复制它并避免 stringifying/parsing...
如有任何帮助,我们将不胜感激!
您不必将对象字符串化即可将其传递给 C++ 插件。有一些方法可以接受那些
任意对象。但它不是那么武断。你必须编写不同的代码来解析 c++ 中的对象。
将其视为数据库的模式。您不能在单个 collection/table 中保存不同格式的数据。
您将需要另一个具有特定架构的 table/collection。
让我们看这个例子:
我们将传递一个对象 {x: 10 , y: 5} 给 addon,c++ addon 将 return 另一个对象与
像这样的属性:{x1:15,y1: 50}
在 cpp 代码中:
NAN_METHOD(func1) {
if (info.Length() > 0) {
Local<Object> obj = info[0]->ToObject();
Local<String> x = Nan::New<String>("x").ToLocalChecked();
Local<String> y = Nan::New<String>("y").ToLocalChecked();
Local<String> sum = Nan::New<String>("sum").ToLocalChecked();
Local<String> prod = Nan::New<String>("prod").ToLocalChecked();
Local<Object> ret = Nan::New<Object>();
double x1 = Nan::Get(obj, x).ToLocalChecked()->NumberValue();
double y1 = Nan::Get(obj, y).ToLocalChecked()->NumberValue();
Nan::Set(ret, sum, Nan::New<Number>(x1 + y1));
Nan::Set(ret, prod, Nan::New<Number>(x1 * y1));
info.GetReturnValue().Set(ret);
}
}
在javascript::
const addon = require('./build/Release/addon.node');
var obj = addon.func1({ 'x': 5, 'y': 10 });
console.log(obj); // { sum: 15, prod: 50 }
这里只能发送{x: (Number), y: (number)}
类型的对象给插件。否则它将无法解析或
检索数据。
像这样的数组:
在 cpp 中:
NAN_METHOD(func2) {
Local<Array> array = Local<Array>::Cast(info[0]);
Local<String> ss_prop = Nan::New<String>("sum_of_squares").ToLocalChecked();
Local<Array> squares = New<v8::Array>(array->Length());
double ss = 0;
for (unsigned int i = 0; i < array->Length(); i++ ) {
if (Nan::Has(array, i).FromJust()) {
// get data from a particular index
double value = Nan::Get(array, i).ToLocalChecked()->NumberValue();
// set a particular index - note the array parameter
// is mutable
Nan::Set(array, i, Nan::New<Number>(value + 1));
Nan::Set(squares, i, Nan::New<Number>(value * value));
ss += value*value;
}
}
// set a non index property on the returned array.
Nan::Set(squares, ss_prop, Nan::New<Number>(ss));
info.GetReturnValue().Set(squares);
}
在javascript中:
const addon = require('./build/Release/addon.node');
var arr = [1, 2, 3];
console.log(addon.func2(arr)); //[ 1, 4, 9, sum_of_squares: 14 ]
这样,你就可以处理数据类型了。如果你想要复杂的对象或操作,你只需
必须将这些方法混合在一个函数中并解析数据。
您可以允许您的 Node.js c++ 插件采用任意类型的参数,但您必须显式检查和处理类型。他是一个简单的示例函数,展示了如何做到这一点:
void args(const Nan::FunctionCallbackInfo<v8::Value>& info) {
int i = 0;
while (i < info.Length()) {
if (info[i]->IsBoolean()) {
printf("boolean = %s", info[i]->BooleanValue() ? "true" : "false");
} else if (info[i]->IsInt32()) {
printf("int32 = %ld", info[i]->IntegerValue());
} else if (info[i]->IsNumber()) {
printf("number = %f", info[i]->NumberValue());
} else if (info[i]->IsString()) {
printf("string = %s", *v8::String::Utf8Value(info[i]->ToString()));
} else if (info[i]->IsObject()) {
printf("[object]");
v8::Local<v8::Object> obj = info[i]->ToObject();
v8::Local<v8::Array> props = obj->GetPropertyNames();
for (unsigned int j = 0; j < props->Length(); j++) {
printf("%s: %s",
*v8::String::Utf8Value(props->Get(j)->ToString()),
*v8::String::Utf8Value(obj->Get(props->Get(j))->ToString())
);
}
} else if (info[i]->IsUndefined()) {
printf("[undefined]");
} else if (info[i]->IsNull()) {
printf("[null]");
}
i += 1;
}
}
为了真正解决处理可能包含具有任意数据的对象的任意参数的问题,我建议编写一个解析实际对象的函数,类似于我解析函数参数的方式在这个例子中。请记住,如果您希望能够处理对象内的嵌套对象,则可能需要递归执行此操作。
我有一个使用 Nan 用 C++ 编写的 Node.js 插件。非常好用。但是,我无法弄清楚如何让我的节点 Javascript 代码将任意数据对象(例如 {attr1:42, attr2:'hi', attr3:[5,4,3,2,1]}
)传递给 C++ 插件。
到目前为止,我已经通过在我的数据对象上调用 JSON.stringify()
然后在 C++ 端解析字符串化 JSON 来解决这个问题。
理想情况下,我想避免复制数据而只是获取对我可以访问的数据对象的引用,或者至少在本机复制它并避免 stringifying/parsing...
如有任何帮助,我们将不胜感激!
您不必将对象字符串化即可将其传递给 C++ 插件。有一些方法可以接受那些 任意对象。但它不是那么武断。你必须编写不同的代码来解析 c++ 中的对象。 将其视为数据库的模式。您不能在单个 collection/table 中保存不同格式的数据。 您将需要另一个具有特定架构的 table/collection。
让我们看这个例子:
我们将传递一个对象 {x: 10 , y: 5} 给 addon,c++ addon 将 return 另一个对象与 像这样的属性:{x1:15,y1: 50}
在 cpp 代码中:
NAN_METHOD(func1) {
if (info.Length() > 0) {
Local<Object> obj = info[0]->ToObject();
Local<String> x = Nan::New<String>("x").ToLocalChecked();
Local<String> y = Nan::New<String>("y").ToLocalChecked();
Local<String> sum = Nan::New<String>("sum").ToLocalChecked();
Local<String> prod = Nan::New<String>("prod").ToLocalChecked();
Local<Object> ret = Nan::New<Object>();
double x1 = Nan::Get(obj, x).ToLocalChecked()->NumberValue();
double y1 = Nan::Get(obj, y).ToLocalChecked()->NumberValue();
Nan::Set(ret, sum, Nan::New<Number>(x1 + y1));
Nan::Set(ret, prod, Nan::New<Number>(x1 * y1));
info.GetReturnValue().Set(ret);
}
}
在javascript::
const addon = require('./build/Release/addon.node');
var obj = addon.func1({ 'x': 5, 'y': 10 });
console.log(obj); // { sum: 15, prod: 50 }
这里只能发送{x: (Number), y: (number)}
类型的对象给插件。否则它将无法解析或
检索数据。
像这样的数组:
在 cpp 中:
NAN_METHOD(func2) {
Local<Array> array = Local<Array>::Cast(info[0]);
Local<String> ss_prop = Nan::New<String>("sum_of_squares").ToLocalChecked();
Local<Array> squares = New<v8::Array>(array->Length());
double ss = 0;
for (unsigned int i = 0; i < array->Length(); i++ ) {
if (Nan::Has(array, i).FromJust()) {
// get data from a particular index
double value = Nan::Get(array, i).ToLocalChecked()->NumberValue();
// set a particular index - note the array parameter
// is mutable
Nan::Set(array, i, Nan::New<Number>(value + 1));
Nan::Set(squares, i, Nan::New<Number>(value * value));
ss += value*value;
}
}
// set a non index property on the returned array.
Nan::Set(squares, ss_prop, Nan::New<Number>(ss));
info.GetReturnValue().Set(squares);
}
在javascript中:
const addon = require('./build/Release/addon.node');
var arr = [1, 2, 3];
console.log(addon.func2(arr)); //[ 1, 4, 9, sum_of_squares: 14 ]
这样,你就可以处理数据类型了。如果你想要复杂的对象或操作,你只需 必须将这些方法混合在一个函数中并解析数据。
您可以允许您的 Node.js c++ 插件采用任意类型的参数,但您必须显式检查和处理类型。他是一个简单的示例函数,展示了如何做到这一点:
void args(const Nan::FunctionCallbackInfo<v8::Value>& info) {
int i = 0;
while (i < info.Length()) {
if (info[i]->IsBoolean()) {
printf("boolean = %s", info[i]->BooleanValue() ? "true" : "false");
} else if (info[i]->IsInt32()) {
printf("int32 = %ld", info[i]->IntegerValue());
} else if (info[i]->IsNumber()) {
printf("number = %f", info[i]->NumberValue());
} else if (info[i]->IsString()) {
printf("string = %s", *v8::String::Utf8Value(info[i]->ToString()));
} else if (info[i]->IsObject()) {
printf("[object]");
v8::Local<v8::Object> obj = info[i]->ToObject();
v8::Local<v8::Array> props = obj->GetPropertyNames();
for (unsigned int j = 0; j < props->Length(); j++) {
printf("%s: %s",
*v8::String::Utf8Value(props->Get(j)->ToString()),
*v8::String::Utf8Value(obj->Get(props->Get(j))->ToString())
);
}
} else if (info[i]->IsUndefined()) {
printf("[undefined]");
} else if (info[i]->IsNull()) {
printf("[null]");
}
i += 1;
}
}
为了真正解决处理可能包含具有任意数据的对象的任意参数的问题,我建议编写一个解析实际对象的函数,类似于我解析函数参数的方式在这个例子中。请记住,如果您希望能够处理对象内的嵌套对象,则可能需要递归执行此操作。