Initial commit
[yaffs-website] / node_modules / nan / doc / object_wrappers.md
1 ## Object Wrappers
2
3 The `ObjectWrap` class can be used to make wrapped C++ objects and a factory of wrapped objects.
4
5  - <a href="#api_nan_object_wrap"><b><code>Nan::ObjectWrap</code></b></a>
6
7
8 <a name="api_nan_object_wrap"></a>
9 ### Nan::ObjectWrap()
10
11 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.
12
13 Definition:
14
15 ```c++
16 class ObjectWrap {
17  public:
18   ObjectWrap();
19
20   virtual ~ObjectWrap();
21
22   template <class T>
23   static inline T* Unwrap(v8::Local<v8::Object> handle);
24
25   inline v8::Local<v8::Object> handle();
26
27   inline Nan::Persistent<v8::Object>& persistent();
28
29  protected:
30   inline void Wrap(v8::Local<v8::Object> handle);
31
32   inline void MakeWeak();
33
34   /* Ref() marks the object as being attached to an event loop.
35    * Refed objects will not be garbage collected, even if
36    * all references are lost.
37    */
38   virtual void Ref();
39
40   /* Unref() marks an object as detached from the event loop.  This is its
41    * default state.  When an object with a "weak" reference changes from
42    * attached to detached state it will be freed. Be careful not to access
43    * the object after making this call as it might be gone!
44    * (A "weak reference" means an object that only has a
45    * persistant handle.)
46    *
47    * DO NOT CALL THIS FROM DESTRUCTOR
48    */
49   virtual void Unref();
50
51   int refs_;  // ro
52 };
53 ```
54
55 See the Node documentation on [Wrapping C++ Objects](https://nodejs.org/api/addons.html#addons_wrapping_c_objects) for more details.
56
57 ### This vs. Holder
58
59 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.
60 The `Signature` installed by [`Nan::SetPrototypeMethod()`](methods.md#api_nan_set_prototype_method) does ensure that `info.Holder()` is just such an instance.
61 In Node 0.12 and later, `info.This()` will also be of such a type, since otherwise the invocation will get rejected.
62 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.
63 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.
64
65 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.
66 So either define your accessors on the instance template,
67 or use `This()` after verifying that it is indeed a valid object.
68
69 ### Examples
70
71 #### Basic
72
73 ```c++
74 class MyObject : public Nan::ObjectWrap {
75  public:
76   static NAN_MODULE_INIT(Init) {
77     v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
78     tpl->SetClassName(Nan::New("MyObject").ToLocalChecked());
79     tpl->InstanceTemplate()->SetInternalFieldCount(1);
80
81     Nan::SetPrototypeMethod(tpl, "getHandle", GetHandle);
82     Nan::SetPrototypeMethod(tpl, "getValue", GetValue);
83
84     constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
85     Nan::Set(target, Nan::New("MyObject").ToLocalChecked(),
86       Nan::GetFunction(tpl).ToLocalChecked());
87   }
88
89  private:
90   explicit MyObject(double value = 0) : value_(value) {}
91   ~MyObject() {}
92
93   static NAN_METHOD(New) {
94     if (info.IsConstructCall()) {
95       double value = info[0]->IsUndefined() ? 0 : Nan::To<double>(info[0]).FromJust();
96       MyObject *obj = new MyObject(value);
97       obj->Wrap(info.This());
98       info.GetReturnValue().Set(info.This());
99     } else {
100       const int argc = 1;
101       v8::Local<v8::Value> argv[argc] = {info[0]};
102       v8::Local<v8::Function> cons = Nan::New(constructor());
103       info.GetReturnValue().Set(cons->NewInstance(argc, argv));
104     }
105   }
106
107   static NAN_METHOD(GetHandle) {
108     MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.Holder());
109     info.GetReturnValue().Set(obj->handle());
110   }
111
112   static NAN_METHOD(GetValue) {
113     MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.Holder());
114     info.GetReturnValue().Set(obj->value_);
115   }
116
117   static inline Nan::Persistent<v8::Function> & constructor() {
118     static Nan::Persistent<v8::Function> my_constructor;
119     return my_constructor;
120   }
121
122   double value_;
123 };
124
125 NODE_MODULE(objectwrapper, MyObject::Init)
126 ```
127
128 To use in Javascript:
129
130 ```Javascript
131 var objectwrapper = require('bindings')('objectwrapper');
132
133 var obj = new objectwrapper.MyObject(5);
134 console.log('Should be 5: ' + obj.getValue());
135 ```
136
137 #### Factory of wrapped objects
138
139 ```c++
140 class MyFactoryObject : public Nan::ObjectWrap {
141  public:
142   static NAN_MODULE_INIT(Init) {
143     v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
144     tpl->InstanceTemplate()->SetInternalFieldCount(1);
145
146     Nan::SetPrototypeMethod(tpl, "getValue", GetValue);
147
148     constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
149   }
150
151   static NAN_METHOD(NewInstance) {
152     v8::Local<v8::Function> cons = Nan::New(constructor());
153     double value = info[0]->IsNumber() ? Nan::To<double>(info[0]).FromJust() : 0;
154     const int argc = 1;
155     v8::Local<v8::Value> argv[1] = {Nan::New(value)};
156     info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
157   }
158
159   // Needed for the next example:
160   inline double value() const {
161     return value_;
162   }
163
164  private:
165   explicit MyFactoryObject(double value = 0) : value_(value) {}
166   ~MyFactoryObject() {}
167
168   static NAN_METHOD(New) {
169     if (info.IsConstructCall()) {
170       double value = info[0]->IsNumber() ? Nan::To<double>(info[0]).FromJust() : 0;
171       MyFactoryObject * obj = new MyFactoryObject(value);
172       obj->Wrap(info.This());
173       info.GetReturnValue().Set(info.This());
174     } else {
175       const int argc = 1;
176       v8::Local<v8::Value> argv[argc] = {info[0]};
177       v8::Local<v8::Function> cons = Nan::New(constructor());
178       info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
179     }
180   }
181
182   static NAN_METHOD(GetValue) {
183     MyFactoryObject* obj = ObjectWrap::Unwrap<MyFactoryObject>(info.Holder());
184     info.GetReturnValue().Set(obj->value_);
185   }
186
187   static inline Nan::Persistent<v8::Function> & constructor() {
188     static Nan::Persistent<v8::Function> my_constructor;
189     return my_constructor;
190   }
191
192   double value_;
193 };
194
195 NAN_MODULE_INIT(Init) {
196   MyFactoryObject::Init(target);
197   Nan::Set(target,
198     Nan::New<v8::String>("newFactoryObjectInstance").ToLocalChecked(),
199     Nan::GetFunction(
200       Nan::New<v8::FunctionTemplate>(MyFactoryObject::NewInstance)).ToLocalChecked()
201   );
202 }
203
204 NODE_MODULE(wrappedobjectfactory, Init)
205 ```
206
207 To use in Javascript:
208
209 ```Javascript
210 var wrappedobjectfactory = require('bindings')('wrappedobjectfactory');
211
212 var obj = wrappedobjectfactory.newFactoryObjectInstance(10);
213 console.log('Should be 10: ' + obj.getValue());
214 ```
215
216 #### Passing wrapped objects around
217
218 Use the `MyFactoryObject` class above along with the following:
219
220 ```c++
221 static NAN_METHOD(Sum) {
222   Nan::MaybeLocal<v8::Object> maybe1 = Nan::To<v8::Object>(info[0]);
223   Nan::MaybeLocal<v8::Object> maybe2 = Nan::To<v8::Object>(info[1]);
224
225   // Quick check:
226   if (maybe1.IsEmpty() || maybe2.IsEmpty()) {
227     // return value is undefined by default
228     return;
229   }
230
231   MyFactoryObject* obj1 =
232     Nan::ObjectWrap::Unwrap<MyFactoryObject>(maybe1.ToLocalChecked());
233   MyFactoryObject* obj2 =
234     Nan::ObjectWrap::Unwrap<MyFactoryObject>(maybe2.ToLocalChecked());
235
236   info.GetReturnValue().Set(Nan::New<v8::Number>(obj1->value() + obj2->value()));
237 }
238
239 NAN_MODULE_INIT(Init) {
240   MyFactoryObject::Init(target);
241   Nan::Set(target,
242     Nan::New<v8::String>("newFactoryObjectInstance").ToLocalChecked(),
243     Nan::GetFunction(
244       Nan::New<v8::FunctionTemplate>(MyFactoryObject::NewInstance)).ToLocalChecked()
245   );
246   Nan::Set(target,
247     Nan::New<v8::String>("sum").ToLocalChecked(),
248     Nan::GetFunction(Nan::New<v8::FunctionTemplate>(Sum)).ToLocalChecked()
249   );
250 }
251
252 NODE_MODULE(myaddon, Init)
253 ```
254
255 To use in Javascript:
256
257 ```Javascript
258 var myaddon = require('bindings')('myaddon');
259
260 var obj1 = myaddon.newFactoryObjectInstance(5);
261 var obj2 = myaddon.newFactoryObjectInstance(10);
262 console.log('sum of object values: ' + myaddon.sum(obj1, obj2));
263 ```