1、return函数
执行函数返回hello world:
1 | #define BUILDING_NODE_EXTENSION |
我们着重看下这2行代码:
Local
Local
fn->SetName(String::NewSymbol(“theFunction”));
FunctionTemplate是用来创建函数的,在一个上下文中仅能创建一个FunctionTemplate,创建的函数的声明周期等于这个上下文存在的声明周期,一个FunctionTemplate可以拥有属性,当你创建它后,这些属性可以加给他。
一个FunctionTemplate可以由原形模版,这个原形模版是用来创建原形链对象的。
下面是V8官网的代码示例:
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); //创建一个函数模版
t->Set("func_property", v8::Number::New(1)); //设置这个函数模版的属性 func_property 为number型1
v8::Local<v8::Template> proto_t = t->PrototypeTemplate(); //定义proto_t指向t的原形链的函数模版,也就是function类,每个函数对象都是function类的实例
proto_t->Set("proto_method", v8::FunctionTemplate::New(InvokeCallback)); //在t的原形链上定义proto_method方法,等于调用InvokeCallback
proto_t->Set("proto_const", v8::Number::New(2));//在function的原形链上增加静态属性2
v8::Local<v8::ObjectTemplate> instance_t = t->InstanceTemplate(); //获得t的实例模版
instance_t->SetAccessor("instance_accessor", InstanceAccessorCallback); //设置访问器
instance_t->SetNamedPropertyHandler(PropertyHandlerCallback, ...);
instance_t->Set("instance_property", Number::New(3));
v8::Local<v8::Function> function = t->GetFunction();//将t转化为js的function对象
v8::Local<v8::Object> instance = function->NewInstance();//实例化t,赋值给instance
下面是js对应的代码:
func_property in function == true;
function.func_property == 1;
function.prototype.proto_method() invokes ‘InvokeCallback’
function.prototype.proto_const == 2;
instance instanceof function == true;
instance.instance_accessor calls ‘InstanceAccessorCallback’
instance.instance_property == 3;
具体我们如何利用c++函数给node用我们了解了,大致的思路是:
先写C++函数,然后利用函数模版转化成js模版函数,接着为这个函数模版做一些属性设置,比如设置原形链或者静态属性等,最后调用这个函数模版指针的GetFunction方法,转化成local
2、包裹c++对象
官网接下来的例子是用C++的类Myobject输出给js,然后js通过new操作来获取它。我们先看代码:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include “myobject.h” //加载myobject文件
using namespace v8;
void InitAll(Handle
NODE_MODULE(addon, InitAll)
我们来看myobject.h的代码:
#ifndef MYOBJECT_H //如果没有定义 MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
class MyObject : public node::ObjectWrap {//声明类Myobject,public继承自node命名空间的ObjectWrap基类
public:
static void Init(v8::Handlev8::Object target); //声明静态方法Init
private:
MyObject(); //声明构造函数
~MyObject(); //声明析构函数
static v8::Handlev8::Value New(const v8::Arguments& args);//声明New方法
static v8::Handlev8::Value PlusOne(const v8::Arguments& args);//声明PlusOne方法
double counter_;
};
#endif
以上是类的定义,我们创建myobject.cc文件
;
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include “myobject.h”
using namespace v8;
MyObject::MyObject() {};
MyObject::~MyObject() {};
void MyObject::Init(Handle
Persistent
//Persistent类表示需要明确的调用Persistent::Dispose才回去GC
target->Set(String::NewSymbol(“MyObject”), constructor); //设置Myobject为构造函数
}
Handle
HandleScope scope;
MyObject* obj = new MyObject();//实例化一个Myobject对象,用obj指针指向
obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); //私有属性counter_初始化
obj->Wrap(args.This());//包裹 args对象
return args.This();
}
Handle
HandleScope scope;
MyObject* obj = ObjectWrap::Unwrap
obj->counter_ += 1; //obj对象的属性counter_加上了1
return scope.Close(Number::New(obj->counter_));//函数返回obj的counter属性
}
这里有几个需要我们仔细消化下:
tpl->InstanceTemplate()->SetInternalFieldCount(1);//设置从这个模版实例化的数量
InstanceTemplate方法用来获得tpl模版的实例的模版,返回Local
Persistent
//Persistent类表示需要明确的调用Persistent::Dispose才回去GC
target->Set(String::NewSymbol(“MyObject”), constructor); //设置Myobject为构造函数
Persistent这个类型不同于local,他不会自动的去GC,而要求用户手动去Dispose,所以这里就等于声明了全局变量,但是在node端这里用Local替换Persistent是一样的。
Javascript中的this指针可以通过Arguments::This ()得到
js代码:
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
3、官网接下来一个例子是用createObject方法来代替new关键字,和上面代码区别只有一块:
Handle
HandleScope scope;
const unsigned argc = 1;
Handle
Local
return scope.Close(instance);
}
官方api对NewInstance的定义:
V8EXPORT Local< Object > NewInstance (int argc, Handle< Value > argv[]) const
注意这里的NewInstance不是MyObject的方法。
js代码:
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
总结一下这2段程序的流程吧:
addon.cc文件
1、定义Init函数,用来初始化,在Init函数中执行Myobject的静态方法Init、
2、Init函数第二行定义一个对外的方法createobject
3、定义createobject方法,执行Myobject类的静态方法NewInstance,然后将其值返回。
myobject.h
1、MYOBJECT_H这个常量如果定义过则不重复定义,如果没有则执行myobject.h,防止重复加载
2、定义Myobject类,继承自node命名空间下的ObjectWrap基类
3、声明2个public的静态方法init和NewInstance
4、声明private的属性和方法,声明构造和析构函数,静态属性 constructor,静态方法new和plusone
最重要的myobject.cc文件,主要是对myobject类各种方法的定义(声明在类中已经做过)
1、将myobject.h包涵进来
2、定义构造和析构函数
3、定义Init函数
3-1、定义一个函数模版,模版来源是c++的myobject类的静态方法new
3-2、设置模版函数tpl的class名,为Myobject
3-3、设置这个class名为myobject的构造函数(js中叫这个吧,不是基类)的原形链上的方法plusone,并且把c++中myobject类的静态私有方法plusone作为函数模版赋值给它
3-4、最后将constructor变量指向tpl转化为的Persistent
4、定义new函数
4-1、创建一个指向Myobject类的实例的指针变量 obj
4-2、将这个实例的counter_属性初始赋值为0或者参数
4-3、将local
4、wrap和unwrap
除了wrap node 对象C++对象以外,我们还可以用过node::ObjectWrap::Unwrap这个方法来unwrap的node对象,供C++使用
wrap.cc代码:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include “myobject.h”
using namespace v8;
Handle
HandleScope scope;
return scope.Close(MyObject::NewInstance(args));
}
Handle
HandleScope scope;
MyObject obj1 = node::ObjectWrap::Unwrap
args[0]->ToObject());//这里告诉我们如何利用Unwrap将node的对象转化为C++的对象
MyObject
args[1]->ToObject());
double sum = obj1->Val() + obj2->Val();
return scope.Close(Number::New(sum));
}
void InitAll(Handle
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* obj1 = node::ObjectWrap::Unwrap
args[0]->ToObject());//这里告诉我们如何利用Unwrap将node的对象转化为C++的对象
我们可以利用这段代码,将node端的对象转化C++端的对象。
mywrap.h
#define BUILDING_NODE_EXTENSION
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
class MyObject : public node::ObjectWrap {
public:
static void Init();
static v8::Handlev8::Value NewInstance(const v8::Arguments& args);
double Val() const { return val_; }
private:
MyObject();
~MyObject();
static v8::Persistentv8::Function constructor;
static v8::Handlev8::Value New(const v8::Arguments& args);
double val_;
};
#endif
mywrap.cc
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include “myobject.h”
using namespace v8;
MyObject::MyObject() {};
MyObject::~MyObject() {};
Persistent
void MyObject::Init() {
// Prepare constructor template
Local
tpl->SetClassName(String::NewSymbol(“MyObject”));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
constructor = Persistent
}
Handle
HandleScope scope;
MyObject* obj = new MyObject();
obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
obj->Wrap(args.This());
return args.This();
}
Handle
HandleScope scope;
const unsigned argc = 1;
Handle
Local
return scope.Close(instance);
}
js代码:
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
这段代码和上面大同小异~