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統合のことはまだ理解していません。私にとって、それはほとんど2つの異なるテンプレートを持っているようなものでした。コンストラクター(およびインスタンスジェネレーター)用の1つの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 に答える