阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      Node.js C++插件 包装对象的工厂

      Node.js C++插件 包装对象的工厂

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

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

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

      // addon.cc
      #include <node.h>
      #include "myobject.h"
      
      namespace demo {
      
      using v8::FunctionCallbackInfo;
      using v8::Isolate;
      using v8::Local;
      using v8::Object;
      using v8::String;
      using v8::Value;
      
      void CreateObject(const FunctionCallbackInfo<Value>& args) {
        MyObject::NewInstance(args);
      }
      
      void InitAll(Local< Object> exports, Local< Object> module) {
        MyObject::Init(exports->GetIsolate());
      
        NODE_SET_METHOD(module, "exports", CreateObject);
      }
      
      NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
      
      }  // namespace demo
      

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

      // 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);
      
       private:
        explicit MyObject(double value = 0);
        ~MyObject();
      
        static void New(const v8::FunctionCallbackInfo< v8::Value>& args);
        static void PlusOne(const v8::FunctionCallbackInfo< v8::Value>& args);
        static v8::Persistent< v8::Function> constructor;
        double value_;
      };
      
      }  // namespace demo
      
      #endif
      

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

      // myobject.cc
      #include <node.h>
      #include "myobject.h"
      
      namespace demo {
      
      using v8::Context;
      using v8::Function;
      using v8::FunctionCallbackInfo;
      using v8::FunctionTemplate;
      using v8::Isolate;
      using v8::Local;
      using v8::Number;
      using v8::Object;
      using v8::Persistent;
      using v8::String;
      using v8::Value;
      
      Persistent< Function> MyObject::constructor;
      
      MyObject::MyObject(double value) : value_(value) {
      }
      
      MyObject::~MyObject() {
      }
      
      void MyObject::Init(Isolate* isolate) {
        // 准备构造函数模版
        Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
        tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
        tpl->InstanceTemplate()->SetInternalFieldCount(1);
      
        // 原型
        NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
      
        constructor.Reset(isolate, tpl->GetFunction());
      }
      
      void MyObject::New(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
      
        if (args.IsConstructCall()) {
          // 像构造函数一样调用:`new MyObject(...)`
          double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
          MyObject* obj = new MyObject(value);
          obj->Wrap(args.This());
          args.GetReturnValue().Set(args.This());
        } else {
          // 像普通方法 `MyObject(...)` 一样调用,转为构造调用。
          const int 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);
        }
      }
      
      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);
      }
      
      void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
      
        MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
        obj->value_ += 1;
      
        args.GetReturnValue().Set(Number::New(isolate, obj->value_));
      }
      
      }  // namespace demo
      

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

      {
        "targets": [
          {
            "target_name": "addon",
            "sources": [
              "addon.cc",
              "myobject.cc"
            ]
          }
        ]
      }
      

      测试:

      // test.js
      const createObject = require('./build/Release/addon');
      
      const obj = createObject(10);
      console.log(obj.plusOne());
      // 打印: 11
      console.log(obj.plusOne());
      // 打印: 12
      console.log(obj.plusOne());
      // 打印: 13
      
      const obj2 = createObject(20);
      console.log(obj2.plusOne());
      // 打印: 21
      console.log(obj2.plusOne());
      // 打印: 22
      console.log(obj2.plusOne());
      // 打印: 23
      

      更多内容请参考:Node.js C++插件,或者通过 点击对应菜单 进行查看;


      目录
      本文目录
      目录