You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					264 lines
				
				8.0 KiB
			
		
		
			
		
	
	
					264 lines
				
				8.0 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								## 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
							 | 
						||
| 
								 | 
							
								   * 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<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));
							 | 
						||
| 
								 | 
							
								```
							 |