All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.doc.object_wrappers.md Maven / Gradle / Ivy

Go to download

Native Abstractions for Node.js: C++ header for Node 0.8 -> 18 compatibility

There is a newer version: 2.19.0
Show newest version
## Object Wrappers

The `ObjectWrap` class can be used to make wrapped C++ objects and a factory of wrapped objects.

 - Nan::ObjectWrap



### Nan::ObjectWrap()

A reimplementation of `node::ObjectWrap` that adds some API not present in older versions of Node. Should be preferred over `node::ObjectWrap` in all cases for consistency.

Definition:

```c++
class ObjectWrap {
 public:
  ObjectWrap();

  virtual ~ObjectWrap();

  template 
  static inline T* Unwrap(v8::Local handle);

  inline v8::Local handle();

  inline Nan::Persistent& persistent();

 protected:
  inline void Wrap(v8::Local handle);

  inline void MakeWeak();

  /* Ref() marks the object as being attached to an event loop.
   * Refed objects will not be garbage collected, even if
   * all references are lost.
   */
  virtual void Ref();

  /* Unref() marks an object as detached from the event loop.  This is its
   * default state.  When an object with a "weak" reference changes from
   * attached to detached state it will be freed. Be careful not to access
   * the object after making this call as it might be gone!
   * (A "weak reference" means an object that only has a
   * persistent handle.)
   *
   * DO NOT CALL THIS FROM DESTRUCTOR
   */
  virtual void Unref();

  int refs_;  // ro
};
```

See the Node documentation on [Wrapping C++ Objects](https://nodejs.org/api/addons.html#addons_wrapping_c_objects) for more details.

### This vs. Holder

When calling `Unwrap`, it is important that the argument is indeed some JavaScript object which got wrapped by a `Wrap` call for this class or any derived class.
The `Signature` installed by [`Nan::SetPrototypeMethod()`](methods.md#api_nan_set_prototype_method) does ensure that `info.Holder()` is just such an instance.
In Node 0.12 and later, `info.This()` will also be of such a type, since otherwise the invocation will get rejected.
However, in Node 0.10 and before it was possible to invoke a method on a JavaScript object which just had the extension type in its prototype chain.
In such a situation, calling `Unwrap` on `info.This()` will likely lead to a failed assertion causing a crash, but could lead to even more serious corruption.

On the other hand, calling `Unwrap` in an [accessor](methods.md#api_nan_set_accessor) should not use `Holder()` if the accessor is defined on the prototype.
So either define your accessors on the instance template,
or use `This()` after verifying that it is indeed a valid object.

### Examples

#### Basic

```c++
class MyObject : public Nan::ObjectWrap {
 public:
  static NAN_MODULE_INIT(Init) {
    v8::Local tpl = Nan::New(New);
    tpl->SetClassName(Nan::New("MyObject").ToLocalChecked());
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    Nan::SetPrototypeMethod(tpl, "getHandle", GetHandle);
    Nan::SetPrototypeMethod(tpl, "getValue", GetValue);

    constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
    Nan::Set(target, Nan::New("MyObject").ToLocalChecked(),
      Nan::GetFunction(tpl).ToLocalChecked());
  }

 private:
  explicit MyObject(double value = 0) : value_(value) {}
  ~MyObject() {}

  static NAN_METHOD(New) {
    if (info.IsConstructCall()) {
      double value = info[0]->IsUndefined() ? 0 : Nan::To(info[0]).FromJust();
      MyObject *obj = new MyObject(value);
      obj->Wrap(info.This());
      info.GetReturnValue().Set(info.This());
    } else {
      const int argc = 1;
      v8::Local argv[argc] = {info[0]};
      v8::Local cons = Nan::New(constructor());
      info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
    }
  }

  static NAN_METHOD(GetHandle) {
    MyObject* obj = Nan::ObjectWrap::Unwrap(info.Holder());
    info.GetReturnValue().Set(obj->handle());
  }

  static NAN_METHOD(GetValue) {
    MyObject* obj = Nan::ObjectWrap::Unwrap(info.Holder());
    info.GetReturnValue().Set(obj->value_);
  }

  static inline Nan::Persistent & constructor() {
    static Nan::Persistent my_constructor;
    return my_constructor;
  }

  double value_;
};

NODE_MODULE(objectwrapper, MyObject::Init)
```

To use in Javascript:

```Javascript
var objectwrapper = require('bindings')('objectwrapper');

var obj = new objectwrapper.MyObject(5);
console.log('Should be 5: ' + obj.getValue());
```

#### Factory of wrapped objects

```c++
class MyFactoryObject : public Nan::ObjectWrap {
 public:
  static NAN_MODULE_INIT(Init) {
    v8::Local tpl = Nan::New(New);
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    Nan::SetPrototypeMethod(tpl, "getValue", GetValue);

    constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
  }

  static NAN_METHOD(NewInstance) {
    v8::Local cons = Nan::New(constructor());
    double value = info[0]->IsNumber() ? Nan::To(info[0]).FromJust() : 0;
    const int argc = 1;
    v8::Local argv[1] = {Nan::New(value)};
    info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
  }

  // Needed for the next example:
  inline double value() const {
    return value_;
  }

 private:
  explicit MyFactoryObject(double value = 0) : value_(value) {}
  ~MyFactoryObject() {}

  static NAN_METHOD(New) {
    if (info.IsConstructCall()) {
      double value = info[0]->IsNumber() ? Nan::To(info[0]).FromJust() : 0;
      MyFactoryObject * obj = new MyFactoryObject(value);
      obj->Wrap(info.This());
      info.GetReturnValue().Set(info.This());
    } else {
      const int argc = 1;
      v8::Local argv[argc] = {info[0]};
      v8::Local cons = Nan::New(constructor());
      info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
    }
  }

  static NAN_METHOD(GetValue) {
    MyFactoryObject* obj = ObjectWrap::Unwrap(info.Holder());
    info.GetReturnValue().Set(obj->value_);
  }

  static inline Nan::Persistent & constructor() {
    static Nan::Persistent my_constructor;
    return my_constructor;
  }

  double value_;
};

NAN_MODULE_INIT(Init) {
  MyFactoryObject::Init(target);
  Nan::Set(target,
    Nan::New("newFactoryObjectInstance").ToLocalChecked(),
    Nan::GetFunction(
      Nan::New(MyFactoryObject::NewInstance)).ToLocalChecked()
  );
}

NODE_MODULE(wrappedobjectfactory, Init)
```

To use in Javascript:

```Javascript
var wrappedobjectfactory = require('bindings')('wrappedobjectfactory');

var obj = wrappedobjectfactory.newFactoryObjectInstance(10);
console.log('Should be 10: ' + obj.getValue());
```

#### Passing wrapped objects around

Use the `MyFactoryObject` class above along with the following:

```c++
static NAN_METHOD(Sum) {
  Nan::MaybeLocal maybe1 = Nan::To(info[0]);
  Nan::MaybeLocal maybe2 = Nan::To(info[1]);

  // Quick check:
  if (maybe1.IsEmpty() || maybe2.IsEmpty()) {
    // return value is undefined by default
    return;
  }

  MyFactoryObject* obj1 =
    Nan::ObjectWrap::Unwrap(maybe1.ToLocalChecked());
  MyFactoryObject* obj2 =
    Nan::ObjectWrap::Unwrap(maybe2.ToLocalChecked());

  info.GetReturnValue().Set(Nan::New(obj1->value() + obj2->value()));
}

NAN_MODULE_INIT(Init) {
  MyFactoryObject::Init(target);
  Nan::Set(target,
    Nan::New("newFactoryObjectInstance").ToLocalChecked(),
    Nan::GetFunction(
      Nan::New(MyFactoryObject::NewInstance)).ToLocalChecked()
  );
  Nan::Set(target,
    Nan::New("sum").ToLocalChecked(),
    Nan::GetFunction(Nan::New(Sum)).ToLocalChecked()
  );
}

NODE_MODULE(myaddon, Init)
```

To use in Javascript:

```Javascript
var myaddon = require('bindings')('myaddon');

var obj1 = myaddon.newFactoryObjectInstance(5);
var obj2 = myaddon.newFactoryObjectInstance(10);
console.log('sum of object values: ' + myaddon.sum(obj1, obj2));
```




© 2015 - 2024 Weber Informatics LLC | Privacy Policy