| ## Object Wrappers | |
| The `ObjectWrap` class can be used to make wrapped C++ objects and a factory of wrapped objects. | |
| - <a href="#api_nan_object_wrap"><b><code>Nan::ObjectWrap</code></b></a> | |
| <a name="api_nan_object_wrap"></a> | |
| ### 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 <class T> | |
| static inline T* Unwrap(v8::Local<v8::Object> handle); | |
| inline v8::Local<v8::Object> handle(); | |
| inline Nan::Persistent<v8::Object>& persistent(); | |
| protected: | |
| inline void Wrap(v8::Local<v8::Object> 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<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(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<double>(info[0]).FromJust(); | |
| MyObject *obj = new MyObject(value); | |
| obj->Wrap(info.This()); | |
| info.GetReturnValue().Set(info.This()); | |
| } else { | |
| const int argc = 1; | |
| v8::Local<v8::Value> argv[argc] = {info[0]}; | |
| v8::Local<v8::Function> cons = Nan::New(constructor()); | |
| info.GetReturnValue().Set(cons->NewInstance(argc, argv)); | |
| } | |
| } | |
| static NAN_METHOD(GetHandle) { | |
| MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.Holder()); | |
| info.GetReturnValue().Set(obj->handle()); | |
| } | |
| static NAN_METHOD(GetValue) { | |
| MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.Holder()); | |
| info.GetReturnValue().Set(obj->value_); | |
| } | |
| static inline Nan::Persistent<v8::Function> & constructor() { | |
| static Nan::Persistent<v8::Function> 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<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New); | |
| tpl->InstanceTemplate()->SetInternalFieldCount(1); | |
| Nan::SetPrototypeMethod(tpl, "getValue", GetValue); | |
| constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); | |
| } | |
| static NAN_METHOD(NewInstance) { | |
| v8::Local<v8::Function> cons = Nan::New(constructor()); | |
| double value = info[0]->IsNumber() ? Nan::To<double>(info[0]).FromJust() : 0; | |
| const int argc = 1; | |
| v8::Local<v8::Value> 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<double>(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<v8::Value> argv[argc] = {info[0]}; | |
| v8::Local<v8::Function> cons = Nan::New(constructor()); | |
| info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked()); | |
| } | |
| } | |
| static NAN_METHOD(GetValue) { | |
| MyFactoryObject* obj = ObjectWrap::Unwrap<MyFactoryObject>(info.Holder()); | |
| info.GetReturnValue().Set(obj->value_); | |
| } | |
| static inline Nan::Persistent<v8::Function> & constructor() { | |
| static Nan::Persistent<v8::Function> my_constructor; | |
| return my_constructor; | |
| } | |
| double value_; | |
| }; | |
| NAN_MODULE_INIT(Init) { | |
| MyFactoryObject::Init(target); | |
| Nan::Set(target, | |
| Nan::New<v8::String>("newFactoryObjectInstance").ToLocalChecked(), | |
| Nan::GetFunction( | |
| Nan::New<v8::FunctionTemplate>(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<v8::Object> maybe1 = Nan::To<v8::Object>(info[0]); | |
| Nan::MaybeLocal<v8::Object> maybe2 = Nan::To<v8::Object>(info[1]); | |
| // Quick check: | |
| if (maybe1.IsEmpty() || maybe2.IsEmpty()) { | |
| // return value is undefined by default | |
| return; | |
| } | |
| MyFactoryObject* obj1 = | |
| Nan::ObjectWrap::Unwrap<MyFactoryObject>(maybe1.ToLocalChecked()); | |
| MyFactoryObject* obj2 = | |
| Nan::ObjectWrap::Unwrap<MyFactoryObject>(maybe2.ToLocalChecked()); | |
| info.GetReturnValue().Set(Nan::New<v8::Number>(obj1->value() + obj2->value())); | |
| } | |
| NAN_MODULE_INIT(Init) { | |
| MyFactoryObject::Init(target); | |
| Nan::Set(target, | |
| Nan::New<v8::String>("newFactoryObjectInstance").ToLocalChecked(), | |
| Nan::GetFunction( | |
| Nan::New<v8::FunctionTemplate>(MyFactoryObject::NewInstance)).ToLocalChecked() | |
| ); | |
| Nan::Set(target, | |
| Nan::New<v8::String>("sum").ToLocalChecked(), | |
| Nan::GetFunction(Nan::New<v8::FunctionTemplate>(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)); | |
| ``` | |