## 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 * persistant 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); SetPrototypeMethod(tpl, "getHandle", GetHandle); 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(cons->NewInstance(argc, argv)); } } 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)); ```