UNPKG

8.23 kBMarkdownView Raw
1## Object Wrappers
2
3The `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
11A 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
13Definition:
14
15```c++
16class 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
55See 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
59When 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.
60The `Signature` installed by [`Nan::SetPrototypeMethod()`](methods.md#api_nan_set_prototype_method) does ensure that `info.Holder()` is just such an instance.
61In Node 0.12 and later, `info.This()` will also be of such a type, since otherwise the invocation will get rejected.
62However, 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.
63In 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
65On 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.
66So either define your accessors on the instance template,
67or use `This()` after verifying that it is indeed a valid object.
68
69### Examples
70
71#### Basic
72
73```c++
74class 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(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
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
125NODE_MODULE(objectwrapper, MyObject::Init)
126```
127
128To use in Javascript:
129
130```Javascript
131var objectwrapper = require('bindings')('objectwrapper');
132
133var obj = new objectwrapper.MyObject(5);
134console.log('Should be 5: ' + obj.getValue());
135```
136
137#### Factory of wrapped objects
138
139```c++
140class 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
195NAN_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
204NODE_MODULE(wrappedobjectfactory, Init)
205```
206
207To use in Javascript:
208
209```Javascript
210var wrappedobjectfactory = require('bindings')('wrappedobjectfactory');
211
212var obj = wrappedobjectfactory.newFactoryObjectInstance(10);
213console.log('Should be 10: ' + obj.getValue());
214```
215
216#### Passing wrapped objects around
217
218Use the `MyFactoryObject` class above along with the following:
219
220```c++
221static 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
239NAN_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
252NODE_MODULE(myaddon, Init)
253```
254
255To use in Javascript:
256
257```Javascript
258var myaddon = require('bindings')('myaddon');
259
260var obj1 = myaddon.newFactoryObjectInstance(5);
261var obj2 = myaddon.newFactoryObjectInstance(10);
262console.log('sum of object values: ' + myaddon.sum(obj1, obj2));
263```