| 1 |
liveuser |
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 |
SetPrototypeMethod(tpl, "getHandle", GetHandle);
|
|
|
82 |
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 |
```
|