首页 > 解决方案 > 如何在 Duktape 中创建 C++ 对象

问题描述

基于http://wiki.duktape.org/HowtoNativeConstructor.html,我可以创建一个 c++ 类并导出到 JavaScript,JavaScript 代码也可以创建对象

但。当我在 C++ 本机代码中创建一个对象时,它无法工作,JavaScript 代码看不到该对象

我从 Duktape 收到错误消息:“TypeError:无法读取属性”

我的代码是:

class Btn
{
public:
  void test()
  {
    printf("%s\r\n", __PRETTY_FUNCTION__);
  }
};

Btn btn;

/* btn.prototype.test */
duk_ret_t btn_test(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);

  duk_push_this(ctx);
  duk_get_prop_string(ctx, -1, "\xff""\xff""Btn");
  Btn *x = static_cast<Btn *>(duk_to_pointer(ctx, -1));
  if (x)
  {
    x->test();
  }
  printf("Btn Addr 0x%08x\r\n", x);
  duk_pop(ctx);

  return 0;
}

duk_ret_t btn_destructor(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);
  return 0;
}

/* btn */
duk_ret_t btn_constructor(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);

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

  duk_push_this(ctx);

  printf("Btn Addr 0x%08x\r\n", &btn);
  duk_push_pointer(ctx, &btn);
  duk_put_prop_string(ctx, -2, "\xff""\xff""Btn");

  duk_push_c_function(ctx, btn_destructor, 1);
  duk_set_finalizer(ctx, -2);

  return 0;
}

void btn_init(duk_context *ctx)
{
  duk_push_c_function(ctx, btn_constructor, 0);
  duk_push_object(ctx);
  duk_push_c_function(ctx, btn_test, 0);
  duk_put_prop_string(ctx, -2, "test");
  duk_put_prop_string(ctx, -2, "prototype");
  duk_put_global_string(ctx, "Btn");
}

duk_ret_t getBtn(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);

  int n = duk_get_top(ctx);
  if (n != 1)
  {
    return DUK_EXEC_ERROR;
  }

  // get "MyButton"
  std::string str(duk_to_string(ctx, 0));

  // create Btn object
  duk_get_global_string(ctx, "Btn");
  duk_new(ctx, 0);

  duk_push_object(ctx);

  return DUK_EXEC_SUCCESS;
}

static duk_ret_t duk__print(duk_context *ctx) {
  duk_push_string(ctx, " ");
  duk_insert(ctx, 0);
  duk_join(ctx, duk_get_top(ctx) - 1);
  printf("%s\n", duk_safe_to_string(ctx, -1));
  return 0;
}

int main(int argc, char *argv[]) {

  duk_context *ctx = duk_create_heap_default();

  duk_push_c_function(ctx, duk__print, DUK_VARARGS);
  duk_put_global_string(ctx, "print");

  btn_init(ctx);

  duk_push_global_object(ctx);
  duk_push_c_function(ctx, getBtn, 1);
  duk_put_prop_string(ctx, -2, "getBtn");
  duk_pop(ctx);

  printf("------- Script 1 -------\r\n");
  {
    std::string script1 = "btn = getBtn(\"MyButton\");" \
        "print(btn);" \
        "btn.test()";

    duk_push_string(ctx, script1.c_str());
    if (duk_peval(ctx) != 0)
    {
      printf("eval failed: %s\n", duk_safe_to_string(ctx, -1));
    }

    duk_pop(ctx);
  }

  printf("------- Script 2 -------\r\n");
  {
    std::string script2 = "btn = new Btn();" \
          "print(btn);" \
          "btn.test();";

    duk_push_string(ctx, script2.c_str());
    if (duk_peval(ctx) != 0)
    {
      printf("eval failed: %s\n", duk_safe_to_string(ctx, -1));
    }

    duk_pop(ctx);
  }

  duk_destroy_heap(ctx);

  return 0;
}

输出结果:

-------- 脚本 1 --------
duk_ret_t getBtn(duk_context*)
duk_ret_t btn_constructor(duk_context*)
Btn 地址 0x00476030
duk_ret_t btn_destructor(duk_context*)
不明确的
评估失败:TypeError:无法读取未定义的属性“测试”
------- 脚本 2 -------
duk_ret_t btn_constructor(duk_context*)
Btn 地址 0x00476030
[对象对象]
duk_ret_t btn_test(duk_context*)
无效 Btn::test()
Btn 地址 0x00476030
duk_ret_t btn_destructor(duk_context*)

如何在getBtn(C++ 本机代码)函数中创建 JavaScript 对象,并将对象返回给 JavaScript 代码?

标签: javascriptc++duktape

解决方案


使用duk_new从 C++ 代码生成 JS 类的实例。此调用需要一个构造函数和 duk 堆栈上的参数。

/* Assume target function is already on stack at func_idx.
 * Equivalent to Ecmascript 'new func("foo", 123)'.
 */
duk_idx_t func_idx = /* ... */;

duk_dup(ctx, func_idx);
duk_push_string(ctx, "foo");
duk_push_int(ctx, 123);
duk_new(ctx, 2);  /* [ ... func "foo" 123 ] -> [ ... res ] */
printf("result is object: %d\n", (int) duk_is_object(ctx, -1));
duk_pop(ctx);

推荐阅读