1# Longque-JS-API使用指导 2Longque JS API 由 Longque JS Engine 提供,适用于在 OpenHarmony 平台构建稳定、高性能的应用。所有 API 均位于 `__Longque__` 对象下。接口的版本可通过 `__Longque__.version` 获得,开发者可使用该版本进行特性判断。 3 4**【注意】:Longque JS API 处于实验阶段,使用前请阅读本文档,评估其稳定性和兼容性。** 5 6## 接口说明 7| 接口 | 功能说明 | 8|----------------------------|-------------------------------------| 9|createDelegate | 创建委托 | 10 11## 属性说明 12| 属性 | 功能说明 | 13|----------------------------|-------------------------------------| 14|version | 用于表示 Longque JS API 的版本| 15|SKIP_PROTOTYPE_CHAIN |createDelegate 的属性过滤器,表示只委托自身属性,不考虑原型链| 16|SKIP_PREFIX_UNDERSCORE |createDelegate 的属性过滤器,表示过滤掉名字以 '_' 开头的属性| 17|SKIP_PREFIX_DOLLAR |createDelegate 的属性过滤器,表示过滤掉名字以 '$' 开头的属性| 18|SKIP_CONSTRUCTOR |createDelegate 的属性过滤器,表示过滤掉 'constructor' 属性| 19 20## createDelegate接口 21> 接口引入版本 : 1 22 23### 接口描述 24| 接口 | 名称 | 说明 | 25| -- | -- | -- | 26| createDelegate | 创建委托 | 创建 `underlyingObject` 的委托对象,对委托对象的属性读写操作将映射至 `underlyingObject`。通过 `initObject` 指定初始委托对象,通过 `propertyFilterFlags` 指定属性过滤器。默认情况下,将映射 `underlyingObject` 及其原型链上所有可枚举的字符串键属性。 27 28### 参数 29(1) `underlyingObject`: 必选参数。表示被委托的底层对象。参数要求: 30- `underlyingObject` 必须是对象,否则会抛出 `TypeError` 异常。 31- 若 `underlyingObject` 是代理对象,将抛出 `TypeError` 异常。 32- 若未指定 `SKIP_PROTOTYPE_CHAIN` 过滤器,且 `underlyingObject` 原型链上存在代理对象,则抛出 `TypeError` 异常。 33 34(2) `initObject`:可选参数。表示初始委托对象。若传入 undefined,表示不指定初始对象,将由接口自动创建。参数要求: 35- `initObject` 必须是对象,否则会抛出 `TypeError` 异常。 36- 若 `initObject` 是代理对象,将抛出 `TypeError` 异常。 37- 不能将委托对象作为 `initObject`,否则抛出 `TypeError` 异常。 38- 若 `initObject` 是不可扩展的,则抛出 `TypeError` 异常。 39- 若 `initObject` 中某些属性无法定义,将抛出 `TypeError` 异常,此时 `initObject` 中仅部分属性定义成功。 40 41(3) `propertyFilterFlags`:可选参数。表示属性过滤器。如果传入的是 undefined,表示不指定过滤器。参数要求: 42- 以下列出了当前支持的属性过滤器(未来可能扩展)。 43```sh 44__Longque__.SKIP_PROTOTYPE_CHAIN: 只委托 underlyingObject 自身属性,不考虑原型链 45__Longque__.SKIP_PREFIX_UNDERSCORE: 过滤掉名字以 '_' 开头的属性 46__Longque__.SKIP_PREFIX_DOLLAR: 过滤掉名字以 '$' 开头的属性 47__Longque__.SKIP_CONSTRUCTOR: 过滤掉 'constructor' 属性 48``` 49- 必须使用列出的过滤器,否则接口行为未定义,可能导致代码兼容性问题。 50- 所有过滤器均为 `number` 类型,可用 | 运算符同时指定多个。 51- 若 `propertyFilterFlags` 非 `number` 类型,抛出 `TypeError` 异常。 52 53### 返回值 54只有接口在不抛出异常的情况下,才会正确返回: 55- 若未指定初始委托对象,返回新创建的委托对象。 56- 若已指定初始委托对象,返回该初始委托对象。 57 58### 注意事项 59(1) 委托对象的属性顺序可能与 for-in、Object.keys 方法的结果不一致,请勿依赖属性顺序。 60 61(2) 委托对象的实现是引擎内部机制。请勿依赖在委托对象上调用 `Object.getOwnPropertyDescriptor`、`getOwnPropertyDescriptors`、`Reflect.getOwnPropertyDescriptor` 等接口的返回结果。 62 63### 使用示例 64 65本示例展示了在 JSVM 中使用 Longque JS API 的方式,JSVM-API 接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++相关代码进行展示。 66 67cpp部分代码: 68``` cpp 69// 待执行的js代码 70static const char *STR_TASK = R"JS( 71 function createDelegateTest() { 72 var myobj = { 73 42: 0, 74 x: 1, 75 _y: 2, 76 $z:3 77 }; 78 79 var proto = { 80 foo: 'foo' 81 }; 82 Object.setPrototypeOf(myobj, proto); 83 84 var d1 = __Longque__.createDelegate(myobj, undefined); 85 consoleinfo(JSON.stringify(d1)); // {"42":0,"x":1,"_y":2,"$z":3,"foo":"foo"} 86 87 const propertyFilterFlags = __Longque__.SKIP_PREFIX_UNDERSCORE | __Longque__.SKIP_PREFIX_DOLLAR; 88 var d2 = __Longque__.createDelegate(myobj, undefined, propertyFilterFlags); 89 consoleinfo(JSON.stringify(d2)); // {"42":0,"x":1,"foo":"foo"} 90 91 d2[42] = 100; 92 93 const newFilter = propertyFilterFlags | __Longque__.SKIP_PROTOTYPE_CHAIN; 94 var d3 = __Longque__.createDelegate(myobj, undefined, newFilter); 95 consoleinfo(JSON.stringify(d3)); // {"42":100,"x":1} 96 } 97 createDelegateTest(); 98)JS"; 99 100// 保证js代码中的打印信息可以正常输出 101static JSVM_Value ConsoleInfo(JSVM_Env env, JSVM_CallbackInfo info) { 102 size_t argc = 1; 103 JSVM_Value args[1]; 104 char log[256] = ""; 105 size_t logLength = 0; 106 JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL)); 107 108 OH_JSVM_GetValueStringUtf8(env, args[0], log, 255, &logLength); 109 log[255] = 0; 110 OH_LOG_INFO(LOG_APP, "JSVM API TEST: %{public}s", log); 111 return nullptr; 112} 113 114// 注册consoleinfo的方法 115JSVM_CallbackStruct param[] = { 116 {.data = nullptr, .callback = ConsoleInfo}, 117}; 118JSVM_PropertyDescriptor descriptor[] = { 119 {"consoleinfo", NULL, ¶m[0], NULL, NULL, NULL, JSVM_DEFAULT}, 120}; 121 122static int32_t TestJSVM() { 123 JSVM_InitOptions init_options; 124 memset(&init_options, 0, sizeof(init_options)); 125 if (g_aa == 0) { 126 OH_JSVM_Init(&init_options); 127 g_aa++; 128 } 129 // 创建JavaScript虚拟机实例,打开虚拟机作用域 130 JSVM_VM vm; 131 JSVM_CreateVMOptions options; 132 memset(&options, 0, sizeof(options)); 133 CHECK(OH_JSVM_CreateVM(&options, &vm)); 134 JSVM_VMScope vm_scope; 135 CHECK(OH_JSVM_OpenVMScope(vm, &vm_scope)); 136 137 JSVM_Env env; 138 CHECK(OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env)); 139 JSVM_EnvScope envScope; 140 CHECK_RET(OH_JSVM_OpenEnvScope(env, &envScope)); 141 JSVM_HandleScope handlescope; 142 CHECK_RET(OH_JSVM_OpenHandleScope(env, &handlescope)); 143 JSVM_Value sourcecodevalue; 144 CHECK_RET(OH_JSVM_CreateStringUtf8(env, STR_TASK, strlen(STR_TASK), &sourcecodevalue)); 145 JSVM_Script script; 146 CHECK_RET(OH_JSVM_CompileScript(env, sourcecodevalue, nullptr, 0, true, nullptr, &script)); 147 JSVM_Value result; 148 CHECK_RET(OH_JSVM_RunScript(env, script, &result)); 149 150 // 关闭并销毁环境和虚拟机 151 CHECK_RET(OH_JSVM_CloseHandleScope(env, handlescope)); 152 CHECK_RET(OH_JSVM_CloseEnvScope(env, envScope)); 153 CHECK(OH_JSVM_DestroyEnv(env)); 154 CHECK(OH_JSVM_CloseVMScope(vm, vm_scope)); 155 CHECK(OH_JSVM_DestroyVM(vm)); 156 return 0; 157} 158``` 159 160预期的输出: 161``` 162JSVM API TEST: {"42":0,"x":1,"_y":2,"$z":3,"foo":"foo"} 163JSVM API TEST: {"42":0,"x":1,"foo":"foo"} 164JSVM API TEST: {"42":100,"x":1} 165```