|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- ## 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(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
- }
- }
-
- 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));
- ```
|