参考V8的英文文档,前面基本上是翻译, 后面是C++和Javascript的调用方式示例
1. Handle
l handle可以理解为指针,所有V8的对象都必须通过Handle来访问,因为V8垃圾收集机制决定了;
l handle都是被v8的垃圾收集器来管理的;
l handle在传递时都采用传值模式
Handle有两种类型:
1. Local Handle继承至Handle:代表局部变量, 它的生命周期有HandleScope来决定,通常都是在调用的函数栈上, HandleScope只能在c++的堆栈上分配,不能用new来分配,HandleScope析构时Local对象同时被释放
2. Persistent Handle继承至Handle:它的生命周期是全局的,释放的时候需要手工调用。
Persistent::New
用于分配对象
Persistent::Dispose
用于释放对象
V8会定期收集垃圾(无效的Handle),垃圾收集的机制是V8性能的关键(分代模式)
2. Scope
Scope可以理解为Handle的容器,可以包含很多很多的Handle。
Scope可以分:HandleScope、Context::Scope
1. 栈分配器,管理所有的Local Handle对象
2. HandleScope是构建在c++栈上面的
3. 它对localhandle的管理范围是在它的生存周期内,直到又创建了一个新的HandleScope
4. 当新分配一个HandleScope之后,新的Local Handle将在新的HandleScope内分配,直到这个HandleScope析构
5. HandleScope析构以后, 它所管理的Local Handle都将被释放,对于js而言,这个时候访问的就是undefined
6. Context::Scope仅仅管理Context,在构造中Context::Enter, 在析构中Context::Leave
3. Isolate
isolate代表了一个独立的v8引擎,简单说它是完全独立的,一个isolate中的对象不能被另外一个isolate使用。可以让每个线程拥有一个不同的isolate,来并行执行不同的JavaScript。对于isolate来说,任何时刻最多只能有一个现在对它访问,因此多线程并在执行同一个isolate的时候,需要有锁机制。
4. Context
Context表示执行环境,JavaScript代码可以运行在不同的执行环境里面,而且必须显示的指定运行在哪个执行环境。
a) 之所有Context,是因为JavaScript有内建的对象,需要隔离不同Context的内建对象
b) 第一次构建Context对象消耗比较大,后面就比较快了(snapshot)
c) 可以从一个Context快速切换到另外一个Context
d) 在C++代码中可以通过Context::GetCurrent()获取当前的Context
5. Template
Template代表了C++中JavaScript中的函数和对象,可以有很多的templates类型,在一个Context中只能有一个具体的Template的实例,有两种类型的template:
1. Function template
2. Object template
ObjectTemplate用于创建javascript中的object,添加到ObjectTemplate中的属性会添加到用ObjectTemplate创建出来的所有Javascript的object中。
1. 每个Function template关联着一个Object template
Handle<ObjectTemplate> global = ObjectTemplate::New(); global->Set(String::New("log"), FunctionTemplate::New(LogCallback));
2. 可以将自己定义的Object作为内嵌类型,以供其他js使用
Persistent<Context> context = Context::New(NULL, global);
6. Accessors
当Object的对象被js访问时被调用,会触发C++的回调函数,有两种类型的Accessor
1. Static Global变量
所谓静态全局变量指的是JavaScript中全局的变量。
Handle<Value> XGetter(Local<String> property, const AccessorInfo& info) { return Integer::New(x); } void XSetter(Local<String> property, Local<Value> value, const AccessorInfo& info) { x = value->Int32Value(); } // YGetter/YSetter are so similar they are omitted for brevity Handle<ObjectTemplate> global_templ = ObjectTemplate::New(); global_templ->SetAccessor(String::New("x"), XGetter, XSetter); global_templ->SetAccessor(String::New("y"), YGetter, YSetter); Persistent<Context> context = Context::New(NULL, global_templ);
2. 动态变量
表示类中的成员变量,比如:
class Point { public: Point(int x, int y) : x_(x), y_(y) { } int x_, y_; }
需要建立一个JavaScript Object和C++对象关联起来(比如很多point对象,如何在JavaScript中管理?)。每个JavaScript对象都需要保存一个索引(成员变量)指向C++对象,但是这个变量在JavaScript中是访问不到,只能在C++中可以访问,可以理解为内部字段。
Handle<ObjectTemplate> point_templ = ObjectTemplate::New();
point_templ->SetInternalFieldCount(1);
这里内部字段的个数设置为1,表示当前对象有一个内部字段(索引为0),指向了C++对象。一个对象可以有多个内部字段。
增加x&y的Accessors:
point_templ.SetAccessor(String::New("x"), GetPointX, SetPointX); point_templ.SetAccessor(String::New("y"), GetPointY, SetPointY);
包装一个C++ 对象,并和JavaScript 的ObjectTemplate关联:
Point* p = ...; Local<Object> obj = point_templ->NewInstance(); obj->SetInternalField(0, External::New(p));
通过NewInstance构建一个实例,然后通过SetInternalField把C++对象和JavaScript对象关联起来。
External 对象只能用于从内部字段中恢复索引,相当于JavaScript对象到C++对象的一个桥接,上面例子中:Local<External> wrap就代表了JavaScript对象。
7. Intercetors
能够指定JavaScript访问对象属性时的一个callback。为了效率的原因,有两种不同的interceptor:
命名属性interceptor:通过属性的名称来访问
索引属性interceptor:通过属性的索引来访问
Handle<ObjectTemplate> result = ObjectTemplate::New(); result->SetNamedPropertyHandler(MapGet, MapSet);
Handle<Value> JsHttpRequestProcessor::MapGet(Local<String> name, const AccessorInfo &info) { // Fetch the map wrapped by this object. map<string, string> *obj = UnwrapMap(info.Holder()); // Convert the JavaScript string to a std::string. string key