调用在Node.js和v8中使用包装对象作为参数的函数

use*_*354 5 c++ binding closures v8 node.js

我想在node.js中执行类似下面的操作...

var a = new A(); var b = new B();

// onTick应该是一个以B的实例作为参数的函数

a.onTick = function(bInst){....}

一个循环();

意味着A有一个属性"onTick",它是一个在循环内调用的函数.注意,A和B被定义为C++包装函数,这里是定义

void AClass::Init(Handle<Object> target) {
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("A"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->PrototypeTemplate()->Set(String::NewSymbol("tick"),
      FunctionTemplate::New(Tick)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("loop"),
  FunctionTemplate::New(Loop)->GetFunction());

  constructor = Persistent<Function>::New(tpl->GetFunction());
  constructor->InstanceTemplate()->SetAccessor(String::New("onTick"), GetOnTick, SetOnTick);
  target->Set(String::NewSymbol("A"), constructor);
}

Handle<Value> AClass::New(const v8::Arguments &args) {
  HandleScope scope;
  AClass* acls = new AClass();
  WrappedAClass* wrappedA = new WrappedAClass();
  acls->wrappedAInst_ = wrappedA;
  window->Wrap(args.This());
  return args.This();
}
Handle<Value> AClass::Loop(const Arguments &args) {
  HandleScope scope;
  AClass* acls = ObjectWrap::Unwrap<AClass>(args.This());
  acls->wrappedInst_->loop();
  return scope.Close(Undefined());
}
Run Code Online (Sandbox Code Playgroud)

我相信这就是你如何设置属性的getter和setter

Handle<Function> GetOnTick(Local<String> property, const AccessorInfo& info) {
  AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder());
  return acls->onTick_;
}

void SetOnTick(Local<String> property, Local<Function> value, const AccessorInfo& info) {
  AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder());

  acls->onTick_ = Persistent<Function>::New(value);
  //Here's where I know I'm doing it wrong
  void func(WrappedClassB* wcb) { 
    const unsigned argc = 1;
    Local<Value> argv[argc] = 
      { Local<Value>::New(BClass::Instantiate(wcb)) };
    acls->onTick_->Call(Context::GetCurrent()->Global(), argc, argv);   
  }
  acls->wrappedAInst_->setTickFunc(func);
}
Run Code Online (Sandbox Code Playgroud)

我要做的是从设置onTick(它接受B类的一个实例)中获取该函数并将其包装在一个实例化新BClass的函数中.

无论如何,这是BClass的定义

Persistent<Function> BClass::constructor;
BClass::BClass() {
}
BClass::~BClass() {
}

void BClass::Init(Handle<Object> target) {
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("B"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("B"), constructor);
}

Handle<Value> BClass::New(const v8::Arguments &args) {
  HandleScope scope;
  BClass* bcls = new BClass();
  bcls->Wrap(args.This());
  WrappedBClass* wrappedB = new WrappedBClass();
  bcls->wrappedBInst_ = wrappedB;
  return args.This();
}
Handle<Value> BClass::Instantiate(const WrappedBClass &wbc) {
  HandleScope scope;
//I know the following is wrong but it shows what I am trying to do
  BClass* bcls = new BClass();
  bcls->wrappedBInst_ = wbc;
  return scope.Close(Local<v8::Value>::New(bcls));
}
Run Code Online (Sandbox Code Playgroud)

无论ACLASS和BClass使用另一个C++类和实例保存为一个属性(wrappedBInst,wrappedAInst)我相信我需要当我需要的WrappedBClass的实例转换成BClass的实例化功能.

WrappedBClass没有做什么特别的,但WrappedAClass继承其具有循环和onTick函数的类,并且onTick功能是我需要调用我的JavaScript函数,所以在WrappedAClass我推翻onTick,并增加了setTickFunc功能.

class WrappedAClass : public InheritedClass{
public:
  void setTickFunc(void (*func)(WrappedBClass*)){
    tickFunc = func;
  }
protected:
  void tickFunc;
  virtual void onTick(WrappedBClass* wbc){
    if(tickFunc){
      tickFunc(wbc);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

因此,我认为我可以进入循环并使用javascript函数作为onTick函数的唯一方法是首先将javascript函数包装到c ++函数中,然后通过调用setTickFunc()来设置该函数.我是以正确的方式来做这件事的吗?

我是一个不错的程序员,但最近刚开始使用C++,所以请原谅我明显的错误,最大的错误很可能就是:

void SetOnTick(Local<String> property, Local<Function> value, const AccessorInfo& info) {
      AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder());

      acls->onTick_ = Persistent<Function>::New(value);
      //Here's where I know I'm doing it wrong
      void func(WrappedClassB* wcb) { 
        const unsigned argc = 1;
        Local<Value> argv[argc] = 
          { Local<Value>::New(BClass::Instantiate(wcb)) };
        acls->onTick_->Call(Context::GetCurrent()->Global(), argc, argv);   
      }
      acls->wrappedAInst_->setTickFunc(func);
    }
Run Code Online (Sandbox Code Playgroud)

我还在试图弄清楚如何创建一个匿名函数来保持外部变量的值(acls).我不认为闭包在这里是有效的,关键是这个函数只有一个参数(WrappedClassB*wcb),因为它需要设置为OnTick函数.

Kev*_*vin 0

您不必在 C++ 中创建匿名函数。WrappedAClass也许你可以这样定义你。

class WrappedAClass : public InheritedClass{
public:
  void setTickFunc(Local<Function> jsFn){
    HandleScope scope;
    jsTickFunc = Persistent<Function>::New(jsTickFunc);
  }
protected:
  Persistent<Function> jsTickFunc;
  virtual void onTick(WrappedBClass* wbc){
    HandleScope scope;
    if(jsTickFunc.IsEmpty())
        return;
    const unsigned argc = 1;
    Local<Value> argv[argc] = 
    { Local<Value>::New(BClass::Instantiate(wcb)) };
    jsTickFunc->Call(Context::GetCurrent()->Global(), argc, argv);  
  }
}
Run Code Online (Sandbox Code Playgroud)

注意该SetOnTick函数,第二个参数的类型为Local<Value>not Local<Function>。C++ 与 js 不同,是静态类型语言。也许你可以定义你的SetOnTickSetter 舔这个:

void SetOnTick(Local<String> property, Local<Value> value, const AccessorInfo& info){
  AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder());
  if (value->IsFunction())
    acls->wrappedAInst_->setTickFunc(Local<Function>::Cast(value));
}
Run Code Online (Sandbox Code Playgroud)