一起读nodejs(四)----插件(addons)

来源:岁月联盟 编辑:exp 时间:2012-09-17

因本人没有c++编译环境,故下面代码没有做测试.

 


    插件(Addons)

    插件是动态被连接到共享的对象.他们可以提供一种c和c++类库结合的能力.Api(目前)还是想当复杂,包括几个类库的知识:


V8 javascript 引擎,一个c++类库.用于和javascript连接接口:创建对象,调用方法,等等.在弄的源码目录树中的dpes/v8/include/v8.h文件中做了说明,也可以在线查看.
libuv,c的事件循环库.在任何时间,一个需要等待一个文件描述符变成可读的事件,等待一个定时器,或者等待一个信号来接受都需要使用libux.就是这样,如果你需要i/o操作,你就需要使用libux.
internal node libraries,node核心库,大部分很重要的库都是node::ObjectWrap的类,方便有调用.
others.可以在deps下查看其他可见的库.
    node总是静态的编译所有的依赖到可执行文件.当编译你的模块时,你不需要担心的连接到任何地方的libs.


    Hello World
    作为开始,让我们来制作一个小插件,下面的代码是和c++等价的js代码:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">exports.hello = function() { return 'world'; };</SPAN> 

exports.hello = function() { return 'world'; };首先我们来创建一个hello.cc:[cpp] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#include <node.h> 
#include <v8.h>  
 
using namespace v8; 
 
Handle<Value> Method(const Arguments& args) { 
  HandleScope scope; 
  return scope.Close(String::New("world")); 

 
void init(Handle<Object> target) { 
  target->Set(String::NewSymbol("hello"), 
      FunctionTemplate::New(Method)->GetFunction()); 

NODE_MODULE(hello, init)</SPAN> 

#include <node.h>
#include <v8.h>

using namespace v8;

Handle<Value> Method(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("world"));
}

void init(Handle<Object> target) {
  target->Set(String::NewSymbol("hello"),
      FunctionTemplate::New(Method)->GetFunction());
}
NODE_MODULE(hello, init)    注意,所有的模块插件必须导出一个初始化的方法:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">void Initialize (Handle<Object> target); 
NODE_MODULE(module_name, Initialize)</SPAN> 

void Initialize (Handle<Object> target);
NODE_MODULE(module_name, Initialize)    因为NODE_MODULE不是一个函数,所以它后面没有分号.(参见hello.h).
    module_name必须要匹配除去node后缀的文件名.
    源代码需要被编译成hello.node,二进制插件.为了这么做我们创建一个叫做binding.gyp的文件,它描述了如何把你的模块编译称类似json格式的配置信息.这个文件将会被node-gyp编译成:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">{ 
  "targets": [ 
    { 
      "target_name": "hello", 
      "sources": [ "hello.cc" ] 
    } 
  ] 
}</SPAN> 

{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "hello.cc" ]
    }
  ]
}    下一步是生成适合当前平台的build文件,用node-gyp configure来做.
    现在你会build目录下发现一个makefile(在unix平台上)或者一个vcxproj文件(在windows上).下一步调用node-gyp build 命令.
    现在你已经有了编译后的.node捆绑文件.这些捆绑文件被放在build/release目录下.
    现在你就可以在node项目hello.js中通过require指向刚刚创建的hello.nod二进制模块插件:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var addon = require('./build/Release/hello'); 
 
console.log(addon.hello()); // 'world'</SPAN> 

var addon = require('./build/Release/hello');

console.log(addon.hello()); // 'world'    更深入的了解可以参考下面的patterns部分,或者https://github.com/arturadib/node-qt提供了一个产品例子.

    插件模型(Addon patterns)
    下面的一些插件模型,可以在你开始学习插件模型时提供帮助.可以通过查阅在线的v8 reference来获取关于多样的v8调用的相关帮助,从v8的 Embedder's Guide中获取对一些概念的使用例如:handles,scopes,function,templates等的解释说明.
    为了使用这些例子,你需要使用node-gyp去编译他们,创建下面的binding.gyp文件:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">{ 
  "targets": [ 
    { 
      "target_name": "addon", 
      "sources": [ "addon.cc" ] 
    } 
  ] 
}</SPAN> 

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ]
    }
  ]
}在不止一个.cc文件的情况下,只需要简单的添加文件名称到source变量数组中即可,例如:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">"sources": ["addon.cc", "myexample.cc"]</SPAN> 

"sources": ["addon.cc", "myexample.cc"]现在你的binding.gyp已经就绪,你可以配置和创建插件了:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">$ node-gyp configure build</SPAN> 

$ node-gyp configure build

    方法参数(Function arguments)
    下面的模型阐述了如何从javascript函数调用中读取参数和返回一个结果.这是大体内容,而亲仅仅只是需要addon.cc而已:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#include <node.h>  
 
using namespace v8; 
 
Handle<Value> Add(const Arguments& args) { 
  HandleScope scope; 
 
  if (args.Length() < 2) { 
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments"))); 
    return scope.Close(Undefined()); 
  } 
 
  if (!args[0]->IsNumber() || !args[1]->IsNumber()) { 
    ThrowException(Exception::TypeError(String::New("Wrong arguments"))); 
    return scope.Close(Undefined()); 
  } 
 
  Local<Number> num = Number::New(args[0]->NumberValue() + 
      args[1]->NumberValue()); 
  return scope.Close(num); 

 
void Init(Handle<Object> target) { 
  target->Set(String::NewSymbol("add"), 
      FunctionTemplate::New(Add)->GetFunction()); 

 
NODE_MODULE(addon, Init)</SPAN> 

#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> Add(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    ThrowException(Exception::TypeError(String::New("Wrong arguments")));
    return scope.Close(Undefined());
  }

  Local<Number> num = Number::New(args[0]->NumberValue() +
      args[1]->NumberValue());
  return scope.Close(num);
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("add"),
      FunctionTemplate::New(Add)->GetFunction());
}

NODE_MODULE(addon, Init)你可以使用下面的代码片段来测试它:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var addon = require('./build/Release/addon'); 
 
console.log( 'This should be eight:', addon.add(3,5) );</SPAN> 

var addon = require('./build/Release/addon');

console.log( 'This should be eight:', addon.add(3,5) );   
    回调(Callbacks)
    在这里你可以把一个javascript函数传递一个c++函数,并且执行他们.这是addon.cc:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#include <node.h>  
 
using namespace v8; 
 
Handle<Value> RunCallback(const Arguments& args) { 
  HandleScope scope; 
 
  Local<Function> cb = Local<Function>::Cast(args[0]); 
  const unsigned argc = 1; 
  Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) }; 
  cb->Call(Context::GetCurrent()->Global(), argc, argv); 
 
  return scope.Close(Undefined()); 

 
void Init(Handle<Object> target) { 
  target->Set(String::NewSymbol("runCallback"), 
      FunctionTemplate::New(RunCallback)->GetFunction()); 

 
NODE_MODULE(addon, Init)</SPAN> 

#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> RunCallback(const Arguments& args) {
  HandleScope scope;

  Local<Function> cb = Local<Function>::Cast(args[0]);
  const unsigned argc = 1;
  Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };
  cb->Call(Context::GetCurrent()->Global(), argc, argv);

  return scope.Close(Undefined());
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("runCallback"),
      FunctionTemplate::New(RunCallback)->GetFunction());
}

NODE_MODULE(addon, Init)运行下面的javascript代码片段来测试它:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var addon = require('./build/Release/addon'); 
 
addon.runCallback(function(msg){ 
  console.log(msg); // 'hello world'  
});</SPAN> 

var addon = require('./build/Release/addon');

addon.runCallback(function(msg){
  console.log(msg); // 'hello world'
});   
    对象工厂(Object factory)
    这个模型阐述了如何创建并且返回一个包裹着c++函数的javascript函数:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#include <node.h>  
 
using namespace v8; 
 
Handle<Value> MyFunction(const Arguments& args) { 
  HandleScope scope; 
  return scope.Close(String::New("hello world")); 

 
Handle<Value> CreateFunction(const Arguments& args) { 
  HandleScope scope; 
 
  Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction); 
  Local<Function> fn = tpl->GetFunction(); 
  fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous  
 
  return scope.Close(fn); 

 
void Init(Handle<Object> target) { 
  target->Set(String::NewSymbol("createFunction"), 
      FunctionTemplate::New(CreateFunction)->GetFunction()); 

 
NODE_MODULE(addon, Init)</SPAN> 

#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> MyFunction(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("hello world"));
}

Handle<Value> CreateFunction(const Arguments& args) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction);
  Local<Function> fn = tpl->GetFunction();
  fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous

  return scope.Close(fn);
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("createFunction"),
      FunctionTemplate::New(CreateFunction)->GetFunction());
}

NODE_MODULE(addon, Init)测试:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var addon = require('./build/Release/addon'); 
 
var fn = addon.createFunction(); 
console.log(fn()); // 'hello world'</SPAN> 

var addon = require('./build/Release/addon');

var fn = addon.createFunction();
console.log(fn()); // 'hello world'   
    包裹c++对象(Wrapping C++ Objects)
    这里我们将为一个c++对象或者类MyObject创建一个包裹器,可以在javascript中通过new操作符可以实例化的那种.首先我们要准备主模块addon.cc:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#include <node.h> 
#include "myobject.h"  
 
using namespace v8; 
 
void InitAll(Handle<Object> target) { 
  MyObject::Init(target); 

 
NODE_MODULE(addon, InitAll)</SPAN> 

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

void InitAll(Handle<Object> target) {
  MyObject::Init(target);
}

NODE_MODULE(addon, InitAll)然后在myobject.h中确保你的包裹器继承自:node::ObjectWrap:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#ifndef MYOBJECT_H 
#define MYOBJECT_H 
 
#include <node.h>  
 
class MyObject : public node::ObjectWrap { 
 public: 
  static void Init(v8::Handle<v8::Object> target); 
 
 private: 
  MyObject(); 
  ~MyObject(); 
 
  static v8::Handle<v8::Value> New(const v8::Arguments& args); 
  static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args); 
  double counter_; 
}; 
 
#endif</SPAN> 

#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init(v8::Handle<v8::Object> target);

 private:
  MyObject();
  ~MyObject();

  static v8::Handle<v8::Value> New(const v8::Arguments& args);
  static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
  double counter_;
};

#endif然后在addon.cc中实现那些你想暴露的各种各样的方法.这里我们通过把plusone方法添加到构造方法的prototype中来暴漏它:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#include <node.h> 
#include "myobject.h"  
 
using namespace v8; 
 
MyObject::MyObject() {}; 
MyObject::~MyObject() {}; 
 
void MyObject::Init(Handle<Object> target) { 
  // Prepare constructor template  
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New); 
  tpl->SetClassName(String::NewSymbol("MyObject")); 
  tpl->InstanceTemplate()->SetInternalFieldCount(1); 
  // Prototype  
  tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), 
      FunctionTemplate::New(PlusOne)->GetFunction()); 
 
  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction()); 
  target->Set(String::NewSymbol("MyObject"), constructor); 

 
Handle<Value> MyObject::New(const Arguments& args) { 
  HandleScope scope; 
 
  MyObject* obj = new MyObject(); 
  obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 
  obj->Wrap(args.This()); 
 
  return args.This(); 

 
Handle<Value> MyObject::PlusOne(const Arguments& args) { 
  HandleScope scope; 
 
  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This()); 
  obj->counter_ += 1; 
 
  return scope.Close(Number::New(obj->counter_)); 
}</SPAN> 

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

MyObject::MyObject() {};
MyObject::~MyObject() {};

void MyObject::Init(Handle<Object> target) {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  // Prototype
  tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
      FunctionTemplate::New(PlusOne)->GetFunction());

  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("MyObject"), constructor);
}

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = new MyObject();
  obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
  obj->Wrap(args.This());

  return args.This();
}

Handle<Value> MyObject::PlusOne(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
  obj->counter_ += 1;

  return scope.Close(Number::New(obj->counter_));
}测试:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var addon = require('./build/Release/addon'); 
 
var obj = new addon.MyObject(10); 
console.log( obj.plusOne() ); // 11  
console.log( obj.plusOne() ); // 12  
console.log( obj.plusOne() ); // 13</SPAN> 

var addon = require('./build/Release/addon');

var obj = new addon.MyObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13   
    包裹对象的工厂(Factory of Wrapped Objects)
    当你们想要在javascript中不使用new操作符实例化的情况下可以创建本地对象,这节内容是有用的.例如:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var obj = addon.createObject(); 
// instead of:  
// var obj = new addon.Object();</SPAN> 

var obj = addon.createObject();
// instead of:
// var obj = new addon.Object();让我们在addon.cc中注册createObject方法:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#include <node.h> 
#include "myobject.h"  
 
using namespace v8; 
 
Handle<Value> CreateObject(const Arguments& args) { 
  HandleScope scope; 
  return scope.Close(MyObject::NewInstance(args)); 

 
void InitAll(Handle<Object> target) { 
  MyObject::Init(); 
 
  target->Set(String::NewSymbol("createObject"), 
      FunctionTemplate::New(CreateObject)->GetFunction()); 

 
NODE_MODULE(addon, InitAll)</SPAN> 

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

Handle<Value> CreateObject(const Arguments& args) {
  HandleScope scope;
  return scope.Close(MyObject::NewInstance(args));
}

void InitAll(Handle<Object> target) {
  MyObject::Init();

  target->Set(String::NewSymbol("createObject"),
      FunctionTemplate::New(CreateObject)->GetFunction());
}

NODE_MODULE(addon, InitAll)在myobject.h中现在我们引入了可以帮助实例化对象的静态方法NewInstance(也就是在javascript中干new的活):[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#ifndef MYOBJECT_H 
#define MYOBJECT_H 
 
#include <node.h>  
 
class MyObject : public node::ObjectWrap { 
 public: 
  static void Init(); 
  static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args); 
 
 private: 
  MyObject(); 
  ~MyObject(); 
 
  static v8::Persistent<v8::Function> constructor; 
  static v8::Handle<v8::Value> New(const v8::Arguments& args); 
  static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args); 
  double counter_; 
}; 
 
#endif</SPAN> 

#define BUILDING_NODE_EXTENSION
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init();
  static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);

 private:
  MyObject();
  ~MyObject();

  static v8::Persistent<v8::Function> constructor;
  static v8::Handle<v8::Value> New(const v8::Arguments& args);
  static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
  double counter_;
};

#endif在myobject.cc中的实现和上面代码是很类似的:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION 
#include <node.h> 
#include "myobject.h"  
 
using namespace v8; 
 
MyObject::MyObject() {}; 
MyObject::~MyObject() {}; 
 
Persistent<Function> MyObject::constructor; 
 
void MyObject::Init() { 
  // Prepare constructor template  
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New); 
  tpl->SetClassName(String::NewSymbol("MyObject")); 
  tpl->InstanceTemplate()->SetInternalFieldCount(1); 
  // Prototype  
  tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), 
      FunctionTemplate::New(PlusOne)->GetFunction()); 
 
  constructor = Persistent<Function>::New(tpl->GetFunction()); 

 
Handle<Value> MyObject::New(const Arguments& args) { 
  HandleScope scope; 
 
  MyObject* obj = new MyObject(); 
  obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 
  obj->Wrap(args.This()); 
 
  return args.This(); 

 
Handle<Value> MyObject::NewInstance(const Arguments& args) { 
  HandleScope scope; 
 
  const unsigned argc = 1; 
  Handle<Value> argv[argc] = { args[0] }; 
  Local<Object> instance = constructor->NewInstance(argc, argv); 
 
  return scope.Close(instance); 

 
Handle<Value> MyObject::PlusOne(const Arguments& args) { 
  HandleScope scope; 
 
  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This()); 
  obj->counter_ += 1; 
 
  return scope.Close(Number::New(obj->counter_)); 
}</SPAN> 

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

MyObject::MyObject() {};
MyObject::~MyObject() {};

Persistent<Function> MyObject::constructor;

void MyObject::Init() {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  // Prototype
  tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
      FunctionTemplate::New(PlusOne)->GetFunction());

  constructor = Persistent<Function>::New(tpl->GetFunction());
}

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = new MyObject();
  obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
  obj->Wrap(args.This());

  return args.This();
}

Handle<Value> MyObject::NewInstance(const Arguments& args) {
  HandleScope scope;

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Object> instance = constructor->NewInstance(argc, argv);

  return scope.Close(instance);
}

Handle<Value> MyObject::PlusOne(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
  obj->counter_ += 1;

  return scope.Close(Number::New(obj->counter_));
}测试:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var addon = require('./build/Release/addon'); 
 
var obj = addon.createObject(10); 
console.log( obj.plusOne() ); // 11  
console.log( obj.plusOne() ); // 12  
console.log( obj.plusOne() ); // 13  
 
var obj2 = addon.createObject(20); 
console.log( obj2.plusOne() ); // 21  
console.log( obj2.plusOne() ); // 22  
console.log( obj2.plusOne() ); // 23</SPAN> 

var addon = require('./build/Release/addon');

var obj = addon.createObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13

var obj2 = addon.createObject(20);
console.log( obj2.plusOne() ); // 21
console.log( obj2.plusOne() ); // 22
console.log( obj2.plusOne() ); // 23   
    任意传递包裹的对象(Passing Wrapped Objects around)
    除了包裹和返回c++对象之外,你可以通过node的node::ObjectWrap::Unwrap帮助函数来传递他们.在下面的addon.cc中我们引进了一个接受两个myobject作为参数的add()方法:[javascript] view plaincopyprint?
#define BUILDING_NODE_EXTENSION 
#include <node.h> 
#include "myobject.h"  
 
using namespace v8; 
 
Handle<Value> CreateObject(const Arguments& args) { 
  HandleScope scope; 
  return scope.Close(MyObject::NewInstance(args)); 

 
Handle<Value> Add(const Arguments& args) { 
  HandleScope scope; 
 
  MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>( 
      args[0]->ToObject()); 
  MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>( 
      args[1]->ToObject()); 
 
  double sum = obj1->Val() + obj2->Val(); 
  return scope.Close(Number::New(sum)); 

 
void InitAll(Handle<Object> target) { 
  MyObject::Init(); 
 
  target->Set(String::NewSymbol("createObject"), 
      FunctionTemplate::New(CreateObject)->GetFunction()); 
 
  target->Set(String::NewSymbol("add"), 
      FunctionTemplate::New(Add)->GetFunction()); 

 
NODE_MODULE(addon, InitAll) 

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

Handle<Value> CreateObject(const Arguments& args) {
  HandleScope scope;
  return scope.Close(MyObject::NewInstance(args));
}

Handle<Value> Add(const Arguments& args) {
  HandleScope scope;

  MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
      args[0]->ToObject());
  MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
      args[1]->ToObject());

  double sum = obj1->Val() + obj2->Val();
  return scope.Close(Number::New(sum));
}

void InitAll(Handle<Object> target) {
  MyObject::Init();

  target->Set(String::NewSymbol("createObject"),
      FunctionTemplate::New(CreateObject)->GetFunction());

  target->Set(String::NewSymbol("add"),
      FunctionTemplate::New(Add)->GetFunction());
}

NODE_MODULE(addon, InitAll)为了让事情变的更有趣,我们在myobject.h中引入了一个公共方法,这样一来我们可以在unwrapping之后探测私有变量:[javascript] view plaincopyprint?
#define BUILDING_NODE_EXTENSION 
#ifndef MYOBJECT_H 
#define MYOBJECT_H 
 
#include <node.h>  
 
class MyObject : public node::ObjectWrap { 
 public: 
  static void Init(); 
  static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args); 
  double Val() const { return val_; } 
 
 private: 
  MyObject(); 
  ~MyObject(); 
 
  static v8::Persistent<v8::Function> constructor; 
  static v8::Handle<v8::Value> New(const v8::Arguments& args); 
  double val_; 
}; 
 
#endif 

#define BUILDING_NODE_EXTENSION
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init();
  static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);
  double Val() const { return val_; }

 private:
  MyObject();
  ~MyObject();

  static v8::Persistent<v8::Function> constructor;
  static v8::Handle<v8::Value> New(const v8::Arguments& args);
  double val_;
};

#endifmyobject.cc的实现还是和上面的很类似:[javascript] view plaincopyprint?
#define BUILDING_NODE_EXTENSION 
#include <node.h> 
#include "myobject.h"  
 
using namespace v8; 
 
MyObject::MyObject() {}; 
MyObject::~MyObject() {}; 
 
Persistent<Function> MyObject::constructor; 
 
void MyObject::Init() { 
  // Prepare constructor template  
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New); 
  tpl->SetClassName(String::NewSymbol("MyObject")); 
  tpl->InstanceTemplate()->SetInternalFieldCount(1); 
 
  constructor = Persistent<Function>::New(tpl->GetFunction()); 

 
Handle<Value> MyObject::New(const Arguments& args) { 
  HandleScope scope; 
 
  MyObject* obj = new MyObject(); 
  obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); 
  obj->Wrap(args.This()); 
 
  return args.This(); 

 
Handle<Value> MyObject::NewInstance(const Arguments& args) { 
  HandleScope scope; 
 
  const unsigned argc = 1; 
  Handle<Value> argv[argc] = { args[0] }; 
  Local<Object> instance = constructor->NewInstance(argc, argv); 
 
  return scope.Close(instance); 

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

MyObject::MyObject() {};
MyObject::~MyObject() {};

Persistent<Function> MyObject::constructor;

void MyObject::Init() {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  constructor = Persistent<Function>::New(tpl->GetFunction());
}

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = new MyObject();
  obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
  obj->Wrap(args.This());

  return args.This();
}

Handle<Value> MyObject::NewInstance(const Arguments& args) {
  HandleScope scope;

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Object> instance = constructor->NewInstance(argc, argv);

  return scope.Close(instance);
}测试:[javascript] 
var addon = require('./build/Release/addon'); 
 
var obj1 = addon.createObject(10); 
var obj2 = addon.createObject(20); 
var result = addon.add(obj1, obj2); 
 
console.log(result); // 30 

var addon = require('./build/Release/addon');

var obj1 = addon.createObject(10);
var obj2 = addon.createObject(20);
var result = addon.add(obj1, obj2);

console.log(result); // 30