4

我有几个简单的 C++ 类,例如:

class Audio {
public:
    Audio(const char *filename, bool async = true);
    ~Audio();

    Audio *play(int fade = 0);
    Audio *pause();
    Audio *loop(int loops = -1);
    Audio *volume(float volume);

我在 JavaScript 中复制了如下结构:

var Audio = function(filename, async) {};
Audio.prototype.Play = function(fade) {};
Audio.prototype.Pause = function() {};
Audio.prototype.Loop = function(loops) {};
Audio.prototype.Volume = function(volume) {};

在阅读了 v8、v8-juice 和大量博客的文档和源代码之后......我找不到关于如何使用 C++ 方法“覆盖”JS 函数的单一参考。

理想情况下,我希望 JS 能够控制类的创建/销毁(这可能吗?),并让这些对象始终指向我的本机函数(PrototypeTemplate?)。

我今天花了一整天的时间阅读与此相关的文章/博客/代码,但我希望找不到一个简单的答案。


为了您的利益,对我的“简单”回答将是这样的(包装器对我来说很好;如果我必须为创建/销毁编写包装器,那没关系):

v8::Local<v8::Function> jsAudioFunction = v8::Local<v8::Function>::Cast(v8::Context::GetCurrent()->Global()->Get(v8::String::New("Audio")));
jsAudioFunction->Setup(/* setup constructor/destructor */);
jsAudioFunction->SetPrototype(/* map native methods to js functions */);
4

2 回答 2

2

虽然这不能回答将本机代码绑定到 JS 对象的问题,但以下是我的劳动成果:

static void jsAudioGC(v8::Persistent<v8::Value> object, void *data) {
    v8::Persistent<v8::Object> obj = v8::Persistent<v8::Object>::Cast(object);
    Audio *audio = static_cast<Audio*>(obj->GetPointerFromInternalField(0));
    if (audio != NULL) {
        obj->SetPointerInInternalField(0, NULL);
        v8::V8::AdjustAmountOfExternalAllocatedMemory(-sizeof(audio));
        delete audio;
    }
    object.Dispose();
}

v8::Handle<v8::Value> jsAudio(const v8::Arguments &args) {
    v8::Persistent<v8::Object>::New(args.This()).MakeWeak(NULL, jsAudioGC);

    Audio *audio = new Audio(get(args[0], ""), get(args[1], true));
    v8::V8::AdjustAmountOfExternalAllocatedMemory(sizeof(audio));
    args.This()->SetPointerInInternalField(0, audio);
    return args.This();
}

v8::Handle<v8::Value> jsAudioPlay(const v8::Arguments &args) {
    Audio *audio = static_cast<Audio*>(args.This()->GetPointerFromInternalField(0));
    if (audio != NULL) audio->play(get(args[0], 0));
    return args.This();
}

在我的 init() 函数内部:

v8::Handle<v8::FunctionTemplate> audio = v8::FunctionTemplate::New(&jsAudio);
audio->PrototypeTemplate()->Set("Play", v8::FunctionTemplate::New(&jsAudioPlay));
audio->InstanceTemplate()->SetInternalFieldCount(1);
globals->Set("Audio", audio);

这完全按照我想要的方式完成了一切;包括正确的实例化和垃圾收集。

我对这种方法的唯一遗憾是我希望能够“只使用定义的内容”。这样,这些函数只有在包含 JS“类”时才可用(可以在 JS IDE 中定义和记录所有函数)。

于 2012-07-18T17:07:04.480 回答
0

好吧,我遇到了同样的问题……但还没有弄清楚 GC 集成的东西。对我来说,这就像拥有两个不同的模板一样。一个用于构造函数(和实例生成器)的 FunctionTemplate 和一个用于带有回调的生成数据的 ObjectTemplate。

这是一个 C++ API 类的示例:

https://github.com/martensms/lycheeJS-adk/blob/master/v8gl/api/script.cpp

下面是 JavaScript 端的样子:

https://github.com/martensms/lycheeJS-adk/blob/master/v8gl/test/04-script.js

我这样做是因为这似乎是通常数据类型的实现方式。也许我稍后会移动原型上的方法,但我会看看这是否有意义。

于 2012-07-24T10:32:24.547 回答