也可以使用一个工厂模式,避免显式地使用 JavaScript 的 new 操作来创建对象实例:

    1. const obj = addon.createObject();
    2. // 而不是:
    3. // const obj = new addon.Object();

    首先,在 addon.cc 中实现 createObject() 方法:

    1. // addon.cc
    2. #include <node.h>
    3. #include "myobject.h"
    4. namespace demo {
    5. using v8::FunctionCallbackInfo;
    6. using v8::Isolate;
    7. using v8::Local;
    8. using v8::Object;
    9. using v8::String;
    10. using v8::Value;
    11. void CreateObject(const FunctionCallbackInfo<Value>& args) {
    12. MyObject::NewInstance(args);
    13. }
    14. void InitAll(Local<Object> exports, Local<Object> module) {
    15. MyObject::Init(exports->GetIsolate());
    16. NODE_SET_METHOD(module, "exports", CreateObject);
    17. }
    18. NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
    19. } // namespace demo

    myobject.h 中,添加静态方法 NewInstance() 来处理实例化对象。 这个方法用来代替在 JavaScript 中使用 new

    1. // myobject.h
    2. #ifndef MYOBJECT_H
    3. #define MYOBJECT_H
    4. #include <node.h>
    5. #include <node_object_wrap.h>
    6. namespace demo {
    7. class MyObject : public node::ObjectWrap {
    8. public:
    9. static void Init(v8::Isolate* isolate);
    10. static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
    11. private:
    12. explicit MyObject(double value = 0);
    13. ~MyObject();
    14. static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
    15. static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
    16. static v8::Global<v8::Function> constructor;
    17. double value_;
    18. };
    19. } // namespace demo
    20. #endif

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

    1. // myobject.cc
    2. #include <node.h>
    3. #include "myobject.h"
    4. namespace demo {
    5. using node::AddEnvironmentCleanupHook;
    6. using v8::Context;
    7. using v8::Function;
    8. using v8::FunctionCallbackInfo;
    9. using v8::FunctionTemplate;
    10. using v8::Global;
    11. using v8::Isolate;
    12. using v8::Local;
    13. using v8::Number;
    14. using v8::Object;
    15. using v8::String;
    16. using v8::Value;
    17. // 注意!这不是线程安全的,此插件不能用于工作线程。
    18. Global<Function> MyObject::constructor;
    19. MyObject::MyObject(double value) : value_(value) {
    20. }
    21. MyObject::~MyObject() {
    22. }
    23. void MyObject::Init(Isolate* isolate) {
    24. // 准备构造函数模版
    25. Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
    26. tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked());
    27. tpl->InstanceTemplate()->SetInternalFieldCount(1);
    28. // 原型
    29. NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
    30. Local<Context> context = isolate->GetCurrentContext();
    31. constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
    32. AddEnvironmentCleanupHook(isolate, [](void*) {
    33. constructor.Reset();
    34. }, nullptr);
    35. }
    36. void MyObject::New(const FunctionCallbackInfo<Value>& args) {
    37. Isolate* isolate = args.GetIsolate();
    38. Local<Context> context = isolate->GetCurrentContext();
    39. if (args.IsConstructCall()) {
    40. // 像构造函数一样调用:`new MyObject(...)`
    41. double value = args[0]->IsUndefined() ?
    42. 0 : args[0]->NumberValue(context).FromMaybe(0);
    43. MyObject* obj = new MyObject(value);
    44. obj->Wrap(args.This());
    45. args.GetReturnValue().Set(args.This());
    46. } else {
    47. // 像普通方法 `MyObject(...)` 一样调用,转为构造调用。
    48. const int argc = 1;
    49. Local<Value> argv[argc] = { args[0] };
    50. Local<Function> cons = Local<Function>::New(isolate, constructor);
    51. Local<Object> instance =
    52. cons->NewInstance(context, argc, argv).ToLocalChecked();
    53. args.GetReturnValue().Set(instance);
    54. }
    55. }
    56. void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
    57. Isolate* isolate = args.GetIsolate();
    58. const unsigned argc = 1;
    59. Local<Value> argv[argc] = { args[0] };
    60. Local<Function> cons = Local<Function>::New(isolate, constructor);
    61. Local<Context> context = isolate->GetCurrentContext();
    62. Local<Object> instance =
    63. cons->NewInstance(context, argc, argv).ToLocalChecked();
    64. args.GetReturnValue().Set(instance);
    65. }
    66. void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
    67. Isolate* isolate = args.GetIsolate();
    68. MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
    69. obj->value_ += 1;
    70. args.GetReturnValue().Set(Number::New(isolate, obj->value_));
    71. }
    72. } // namespace demo

    要构建这个例子,myobject.cc 文件必须被添加到 binding.gyp

    1. {
    2. "targets": [
    3. {
    4. "target_name": "addon",
    5. "sources": [
    6. "addon.cc",
    7. "myobject.cc"
    8. ]
    9. }
    10. ]
    11. }

    测试:

    1. // test.js
    2. const createObject = require('./build/Release/addon');
    3. const obj = createObject(10);
    4. console.log(obj.plusOne());
    5. // 打印: 11
    6. console.log(obj.plusOne());
    7. // 打印: 12
    8. console.log(obj.plusOne());
    9. // 打印: 13
    10. const obj2 = createObject(20);
    11. console.log(obj2.plusOne());
    12. // 打印: 21
    13. console.log(obj2.plusOne());
    14. // 打印: 22
    15. console.log(obj2.plusOne());
    16. // 打印: 23