SetCallAsFunctionHandler 相当于lua __call

来源:互联网 发布:用友软件怎么样 编辑:程序博客网 时间:2024/04/27 17:23

首先到google开发者网站上下载v8源码,并按照说明进行编译。

v8中,编译和执行的js代码需要依付于一个空间(上下文)。上下文由Context::New创建。

static Persistent<Context> New(
      ExtensionConfiguration* extensions = NULL,
      Handle<ObjectTemplate> global_template = Handle<ObjectTemplate>(),
      Handle<Value> global_object = Handle<Value>());

其中,extensions表示要增加到上下文的额外配置。global_template指定产生上下文内部对象的对象模板。global_object是要重用的上下文内部对象(该对象是以前由Context::New创建出来的上下文内部对象,且其对象模板必须和global_template相同)。要注意的是,如果指定了global_object,则该global_object除了对象标识会被保留外,其它状态全部重置。

上下文就是js中通过对象模拟出来的命名空间:

function namespace_template()
{

    return {};

}

var Namespace = new namespace_template();

with(Namespace)
{

    ...

};

Persistent<Context> context = Context::New(NULL, namespace_template,NULL);//此处的namespace_template仅表示对应关系

Local<Object> Namespace = context->Global();

要使用上下文,需调用:context->Enter();

接下来,编译运行js代码:

Local<Script> script = Script::Compile(String::New("function add(a, b){return a+b;}"));

script->Run();

Script::Compile:在当前上下文中编译js代码。调用Run时,使用的是Script::Compile时的上下文。

Script::New:独立编译js代码。调用Run时,使用的是调用Run时的上下文。

调用JS中的函数:

Local<Value> value_add = Namespace->Get(String::New("add"));

ASSERT(value_add->IsFunction());

Local<Function> fun_add = Local<Function>::Cast(value_add);

Handle<Value> args[2];

args[0] = Uint32::New(1);

args[1] = Uint32::New(2);

Local<Value> result_add = fun_add->Call(Namespace, 2, args);

ASSERT(result_add->IsUint32());

uint32_t ui_result_add = result_add->Uint32Value();

绑定函数(让js调用VC中的代码):

假设VC中的代码为:

int ave(int a, int b, int c){return (a+b+c)/3;}

希望在js中可直接进行如下调用:

var ave_value = ave(10, 20, 3.);

v8无法将C/C++中的函数直接导出,需要一定的转换:

Handle<Value> ave_js(const Arguments& args)

    if(args.Length() < 3) return Undefined();

    int ave_value = ave(args[0]->Int32Value(), args[1]->Int32Value(), args[2]->Int32Value());
    return Int32::New(ave_value);
}

Namespace->Set(String::New("ave"), FunctionTemplate::New(ave_js)->GetFunction());

绑定对象:

假设VC中有一个CRectangle类对象rectangle(在实际使用中要考虑生命周期):

class CRectangle
{

public:

    int w;

    int h;

    int Area() const{return w * h;}

}rectangle;

希望在js中进行如下调用:

rectangle.w = 10;

rectangle.h = 20;

var area = rectangle.Area();

实现:

Handle<Value> Rectangle_Area(const Arguments& args)
{
 Handle<External> field = Handle<External>::Cast(args.Holder()->GetInternalField(0));
 void* raw_rectangle_ptr = field->Value();
 CRectangle* pRectangle = static_cast<CRectangle*>(raw_rectangle_ptr);
 int area_value = pRectangle->Area();

 return Int32::New(area_value);
}

Handle<Value> Rectangle_Getter(Local<String> property, const AccessorInfo& info)
{
 Local<String> sw = String::New("w");
 Local<String> sh = String::New("h");
 Local<String> sarea = String::New("Area");

 Handle<External> field = Handle<External>::Cast(info.Holder()->GetInternalField(0));
 void* raw_rectangle_ptr = field->Value();
 CRectangle* pRectangle = static_cast<CRectangle*>(raw_rectangle_ptr);

 if(property->StrictEquals(sw)) return Int32::New(pRectangle->w);
 if(property->StrictEquals(sh)) return Int32::New(pRectangle->h);
 if(property->StrictEquals(sarea))
 {
  static Local<Function> Area_Fun = FunctionTemplate::New(Rectangle_Area)->GetFunction();
  return Area_Fun;
 }
 return Undefined();
}

Handle<Value> Rectangle_Setter(Local<String> property, Local<Value> value, const AccessorInfo& info)
{
 Local<String> sw = String::New("w");
 Local<String> sh = String::New("h");
 Local<String> sarea = String::New("Area");

 Handle<External> field = Handle<External>::Cast(info.Holder()->GetInternalField(0)) ;
 void* raw_rectangle_ptr = field->Value();
 CRectangle* pRectangle = static_cast<CRectangle*>(raw_rectangle_ptr);

 if(property->StrictEquals(sw)) return Int32::New(pRectangle->w = value->Int32Value());
 if(property->StrictEquals(sh)) return Int32::New(pRectangle->h = value->Int32Value());

 return Undefined();
}

Local<ObjectTemplate> rectangle_template = ObjectTemplate::New();
rectangle_template->SetInternalFieldCount(1); 
rectangle_template->SetNamedPropertyHandler(Rectangle_Getter, Rectangle_Setter);
rectangle_template->Set(String::New("w"), Int32::New(0));//由于设置了属性访问器和设置器,传入的Int32::New(0)不会被使用
rectangle_template->Set(String::New("h"), Int32::New(0));//由于设置了属性访问器和设置器,传入的Int32::New(0)不会被使用
rectangle_template->Set(String::New("Area"), Int32::New(0));//由于设置了属性访问器和设置器,传入的Int32::New(0)不会被使用

Local<Object> rectangle_obj = rectangle_template->NewInstance();

rectangle_obj->SetInternalField(0, External::New(&rectangle));

Namespace->Set(String::New("rectangle"), rectangle_obj);

导出类(js中的构造函数):

希望在js中生成一个Rectangle类:

function Rectangle(w, h)

{

    this.w = w;

    this.h = h;

    this.Area = function(){return this.w * this.h;}

}

进行如下调用:

var rectangle = new Rectangle(10, 20);

var area = rectangle.Area();

rectangle.w = 1;

rectangle.h = 2;

area = rectangle.Area(); 

实现:

Handle<Value> CRectangle_Area(const Arguments& args)
{
 Local< Object > pThis = args.This();
 int w = pThis->Get(String::New("w"))->Int32Value();
 int h = pThis->Get(String::New("h"))->Int32Value();

 return Int32::New(w*h);
}
Handle<Value> Rectangle_InvocationCallback(const Arguments& args)
{
 Local< Object > pThis = args.This() ;
 int w = 0, h = 0;
 if(args.Length() > 0) w = args[0]->Int32Value();
 if(args.Length() > 1) h = args[1]->Int32Value();
 pThis->Set(String::New("w"), Int32::New(w));
 pThis->Set(String::New("h"), Int32::New(h));

 return pThis;
}


 

Local< FunctionTemplate > Rectangle_template = FunctionTemplate::New();

Local<ObjectTemplate> Rectangle_instance_template = Rectangle_template->InstanceTemplate();
Rectangle_instance_template->SetCallAsFunctionHandler(Rectangle_InvocationCallback);
Rectangle_instance_template->Set("w", Number::New(0));
Rectangle_instance_template->Set("h", Number::New(0));
Rectangle_instance_template->Set("Area", FunctionTemplate::New(CRectangle_Area));

Local<Function> Rectangle_function = Rectangle_template->GetFunction();
Local<Object> Rectangle = Rectangle_function->NewInstance();


Namespace
->Set(String::New("Rectangle"), Rectangle);

完整源码请查看本人发布的资源

0 0
原创粉丝点击