Построить новый объект JU DUKTAPE из c с помощью нативного c-construstor

Я пытаюсь построить объект JS полностью в C, похожий на следующий JS:

var _a = function(p){
    this.p = p;           
}

_a.prototype.myFunction= function(){ ...; }

var _b = function(){
   this.sub = new _a(p);
}

exports.A = A;
exports.B = B;

Тот факт, что он используется в модуле NodeJS, очень важен, потому что ни A, ни B не доступны глобально.

Для этого я написал следующий шаблон на C:

duk_ret_t _js_a_dtor(duk_context *ctx) {
}

duk_ret_t _js_a_ctor(duk_context *ctx) {

    if (!duk_is_constructor_call(ctx)) {
        return DUK_RET_TYPE_ERROR;
    }

    // Push special this binding to the function being constructed
    duk_push_this(ctx);

    // Store the function destructor
    duk_push_c_function(ctx, _js_a_dtor, 0);
    duk_set_finalizer(ctx, -2);
    return 0;
}

duk_ret_t _js_a_myFunction(duk_context *ctx) {
...
}

static const duk_function_list_entry _js_a_funcs[] = {
    { "", _js_a_myFunction, 0 },
    { NULL, NULL, 0 }
};


duk_ret_t _js_b_dtor(duk_context *ctx) {
}

duk_ret_t _js_b_ctor(duk_context *ctx) {

    if (!duk_is_constructor_call(ctx)) {
        return DUK_RET_TYPE_ERROR;
    }

    // Push special this binding to the function being constructed
    duk_push_this(ctx);

    duk_push_c_function(ctx, _js_a_ctor, 0);
    duk_new(ctx,0);
    duk_put_prop_string(ctx,"sub");

    // Store the function destructor
    duk_push_c_function(ctx, _js_b_dtor, 0);
    duk_set_finalizer(ctx, -2);
    return 0;
}

void duk_init_class(duk_context *ctx, void * ctor, int paramsCount, duk_function_list_entry * func, char * className)
{
    // Create object function
    duk_push_c_function(ctx, ctor, paramsCount);       // [{exports},{ctor}]

    // Create a prototype with all functions
    duk_push_object(ctx);                              // [{exports}, { ctor }, {}]
    duk_put_function_list(ctx, -1, func);              // [{exports}, { ctor }, {}]
    duk_put_prop_string(ctx, -2, DUK_PROTOTYPE_NAME);  // [{exports}, { ctor }]

    // Now store the object function
    duk_put_prop_string(ctx, -2, className);           // [{exports}]
}

но, как я подозревал, прототип a, не правильно установлен при вызове duk_new, и любая попытка использовать функцию в JS не удалась

var m = require('mymodule');
var a = new m.A();  // working
a.myFunction();     // working
var b = new m.B();  // working
b.sub ;             // defined
b.sub.myFunction(); // failed while myFunction is undefined.. 

Любая идея о том, как это исправить? я уже знаю, что могу поместить конструктор в глобальный, но я думаю, есть ли другая прямая альтернатива, чтобы связать прототип с функцией c...

С уважением.

1 ответ

Решение

Функции Duktape/C не имеют .prototype свойство по умолчанию, поэтому, когда они вызываются как конструкторы, созданные экземпляры наследуются от Object.prototype. Чтобы изменить это, вы можете просто установить .prototype свойство функции.

Так что, если я правильно понял, в вашем случае вы можете сделать что-то вроде:

/* Build prototype object, here: { myFunction: ... } */
duk_push_object(ctx);
duk_push_c_function(ctx, _js_a_myFunction, ...);
duk_put_prop_string(ctx, -2, "myFunction");

/* Set A.prototype. */
duk_put_prop_string(ctx, idx_for_A_ctor, "prototype");

Если вы используете duk_put_function_list(), вам нужно прочитать значение функции конструктора из целевого объекта, чтобы вы могли установить его .prototype,

Другие вопросы по тегам