传递封装的对象


\Passing wrapped objects around

除了封装和返回 C++ 对象之外,还可以通过使用 Node.js 辅助函数 node::ObjectWrap::Unwrap 将它们解包来传递被封装的对象。以下示例显示了函数 add(),它可以将两个 MyObject 对象作为输入参数:

\In addition to wrapping and returning C++ objects, it is possible to pass wrapped objects around by unwrapping them with the Node.js helper function node::ObjectWrap::Unwrap. The following examples shows a function add() that can take two MyObject objects as input arguments:

// addon.cc
#include <node.h>
#include <node_object_wrap.h>
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
 MyObject::NewInstance(args);
}
void Add(const FunctionCallbackInfo<Value>& args) {
 Isolate* isolate = args.GetIsolate();
 Local<Context> context = isolate->GetCurrentContext();
 MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
 args[0]->ToObject(context).ToLocalChecked());
 MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
 args[1]->ToObject(context).ToLocalChecked());
 double sum = obj1->value() + obj2->value();
 args.GetReturnValue().Set(Number::New(isolate, sum));
}
void InitAll(Local<Object> exports) {
 MyObject::Init(exports->GetIsolate());
 NODE_SET_METHOD(exports, "createObject", CreateObject);
 NODE_SET_METHOD(exports, "add", Add);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo 

myobject.h 中,添加了新的公共方法,以允许在解封装对象后访问私有值。

\In myobject.h, a new public method is added to allow access to private values after unwrapping the object.

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
 public:
 static void Init(v8::Isolate* isolate);
 static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
 inline double value() const { return value_; }
 private:
 explicit MyObject(double value = 0);
 ~MyObject();
 static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
 static v8::Global<v8::Function> constructor;
 double value_;
};
} // namespace demo
#endif 

myobject.cc 的实现与之前类似:

\The implementation of myobject.cc is similar to before:

// myobject.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using node::AddEnvironmentCleanupHook;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Global;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
// Warning! This is not thread-safe, this addon cannot be used for worker
// threads.
Global<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Isolate* isolate) {
 // Prepare constructor template
 Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
 tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked());
 tpl->InstanceTemplate()->SetInternalFieldCount(1);
 Local<Context> context = isolate->GetCurrentContext();
 constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
 AddEnvironmentCleanupHook(isolate, [](void*) {
 constructor.Reset();
 }, nullptr);
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
 Isolate* isolate = args.GetIsolate();
 Local<Context> context = isolate->GetCurrentContext();
 if (args.IsConstructCall()) {
 // Invoked as constructor: `new MyObject(...)`
 double value = args[0]->IsUndefined() ?
 0 : args[0]->NumberValue(context).FromMaybe(0);
 MyObject* obj = new MyObject(value);
 obj->Wrap(args.This());
 args.GetReturnValue().Set(args.This());
 } else {
 // Invoked as plain function `MyObject(...)`, turn into construct call.
 const int argc = 1;
 Local<Value> argv[argc] = { args[0] };
 Local<Function> cons = Local<Function>::New(isolate, constructor);
 Local<Object> instance =
 cons->NewInstance(context, argc, argv).ToLocalChecked();
 args.GetReturnValue().Set(instance);
 }
}
void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
 Isolate* isolate = args.GetIsolate();
 const unsigned argc = 1;
 Local<Value> argv[argc] = { args[0] };
 Local<Function> cons = Local<Function>::New(isolate, constructor);
 Local<Context> context = isolate->GetCurrentContext();
 Local<Object> instance =
 cons->NewInstance(context, argc, argv).ToLocalChecked();
 args.GetReturnValue().Set(instance);
}
} // namespace demo 

测试它:

\Test it with:

// test.js
const addon = require('./build/Release/addon');
const obj1 = addon.createObject(10);
const obj2 = addon.createObject(20);
const result = addon.add(obj1, obj2);
console.log(result);
// Prints: 30 

AltStyle によって変換されたページ (->オリジナル) /