Subversion Repositories qbpwcf-lib(archive)

Rev

Rev 915 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
```