1# 使用JSVM进行class相关开发 2 3## 简介 4 5使用JSVM-API接口进行class相关开发,处理JavaScript中的类,例如定义类、构造实例等。 6 7## 基本概念 8 9在使用JSVM-API接口进行class相关开发时,需要理解以下基本概念: 10 11- **类**:类是用于创建对象的模板。它提供了一种封装数据和行为的方式,以便于对数据进行处理和操作。类在JavaScript中是建立在原型(prototype)的基础上的,并且还引入了一些类独有的语法和语义。 12- **实例**:实例是通过类创建具体的对象。类定义了对象的结构和行为,而实例则是类的具体表现。通过实例化类,我们可以访问类中定义的属性和方法,并且每个实例都具有自己的属性值。 13 14## 接口说明 15 16| 接口 | 功能说明 | 17| ------------------- | ---------------------------------- | 18| OH_JSVM_NewInstance | 通过给定的构造函数,构建一个实例| 19| OH_JSVM_GetNewTarget | 获取函数的元属性new.target| 20| OH_JSVM_DefineClass | 用于在JavaScript中定义一个类,并与对应的C类进行封装和交互。它提供了创建类的构造函数、定义属性和方法的能力,以及在C和JavaScript之间进行数据交互的支持| 21| OH_JSVM_Wrap | 在JavaScript对象中封装原生实例。稍后可以使用OH_JSVM_Unwrap()解包原生实例| 22| OH_JSVM_Unwrap | 解包先前封装在JavaScript对象中的原生实例| 23| OH_JSVM_RemoveWrap | 解包先前封装在JavaScript对象中的原生实例并释放封装| 24|OH_JSVM_DefineClassWithOptions | 定义一个具有给定类名、构造函数、属性和回调处理程序、父类的JavaScript类,并根据传入了DefineClassOptions来决定是否需要为所定义的Class设置属性代理、预留internal-field槽位、为class作为函数进行调用时设置函数回调。| 25 26## 使用示例 27 28JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++相关代码进行展示。 29 30### OH_JSVM_NewInstance 31 32通过给定的构造函数,构建一个实例。 33 34cpp部分代码 35 36```cpp 37// hello.cpp 38#include <string.h> 39 40std::string ToString(JSVM_Env env, JSVM_Value val) { 41 JSVM_Value jsonString; 42 JSVM_CALL(OH_JSVM_JsonStringify(env, val, &jsonString)); 43 size_t totalLen = 0; 44 JSVM_CALL(OH_JSVM_GetValueStringUtf8(env, jsonString, nullptr, 0, &totalLen)); 45 size_t needLen = totalLen + 1; 46 char* buff = new char[needLen]; 47 std::memset(buff, 0, needLen); 48 JSVM_CALL(OH_JSVM_GetValueStringUtf8(env, jsonString, buff, needLen, &totalLen)); 49 std::string str(buff); 50 delete[] buff; 51 return str; 52} 53 54// OH_JSVM_NewInstance的样例方法 55static JSVM_Value NewInstance(JSVM_Env env, JSVM_CallbackInfo info) { 56 // 获取js侧传入的两个参数 57 size_t argc = 2; 58 JSVM_Value args[2] = {nullptr}; 59 JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr)); 60 JSVM_Value result = nullptr; 61 // 调用OH_JSVM_NewInstance接口,实例化一个对象,将这个对象返回 62 JSVM_CALL(OH_JSVM_NewInstance(env, args[0], 1, &args[1], &result)); 63 std::string str = ToString(env, result); 64 OH_LOG_INFO(LOG_APP, "NewInstance:%{public}s", str.c_str()); 65 return nullptr; 66} 67 68// 通过给定的构造函数,构建一个实例。 69// NewInstance注册回调 70static JSVM_CallbackStruct param[] = { 71 {.data = nullptr, .callback = NewInstance}, 72}; 73 74static JSVM_CallbackStruct *method = param; 75 76// NewInstance方法别名,供JS调用 77static JSVM_PropertyDescriptor descriptor[] = { 78 {"newInstance", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 79}; 80``` 81 82#### 样例JS 83 84const char *srcCallNative = R"JS( 85 function Fruit(name) { 86 this.name = name; 87 } 88 newInstance(Fruit, "apple"); 89)JS"; 90 91#### 执行结果 92 93在LOG中输出下面的结果: 94NewInstance:{"name":"apple"} 95 96### OH_JSVM_GetNewTarget 97 98用于获取函数的元属性new.target值。在JavaScript中,new.target是一个特殊的元属性,用于检测函数或构造函数是否是通过 'new' 运算符被调用的。 99 100### OH_JSVM_DefineClass 101 102用于在JavaScript中定义一个类,并与对应的C类进行封装和交互。它提供了创建类的构造函数、定义属性和方法的能力,以及在C和JavaScript之间进行数据交互的支持 103 104cpp部分代码 105 106```cpp 107// hello.cpp 108#include <string> 109 110JSVM_Value CreateInstance(JSVM_Env env, JSVM_CallbackInfo info) { 111 JSVM_Value newTarget; 112 // 获取构造函数的new.target值 113 JSVM_CALL(OH_JSVM_GetNewTarget(env, info, &newTarget)); 114 OH_LOG_INFO(LOG_APP, "Create Instance"); 115 OH_LOG_INFO(LOG_APP, "NAPI MyObject::New %{public}s", newTarget != nullptr ? "newTarget != nullptr" : "newTarget == nullptr"); 116 JSVM_Value jsObject = nullptr; 117 JSVM_CALL(OH_JSVM_CreateObject(env, &jsObject)); 118 JSVM_Value jsName = nullptr; 119 JSVM_CALL(OH_JSVM_CreateStringUtf8(env, "name", JSVM_AUTO_LENGTH, &jsName)); 120 JSVM_Value jsValue = nullptr; 121 JSVM_CALL(OH_JSVM_CreateStringUtf8(env, "lilei", JSVM_AUTO_LENGTH, &jsValue)); 122 JSVM_CALL(OH_JSVM_SetProperty(env, jsObject, jsName, jsValue)); 123 return jsObject; 124} 125 126std::string ToString(JSVM_Env env, JSVM_Value val) { 127 JSVM_Value jsonString; 128 JSVM_CALL(OH_JSVM_JsonStringify(env, val, &jsonString)); 129 size_t totalLen = 0; 130 JSVM_CALL(OH_JSVM_GetValueStringUtf8(env, jsonString, nullptr, 0, &totalLen)); 131 size_t needLen = totalLen + 1; 132 char* buff = new char[needLen]; 133 std::memset(buff, 0, needLen); 134 JSVM_CALL(OH_JSVM_GetValueStringUtf8(env, jsonString, buff, needLen, &totalLen)); 135 std::string str(buff); 136 delete[] buff; 137 return str; 138} 139 140// 封装c++中的自定义数据结构 141JSVM_Value DefineClass(JSVM_Env env, JSVM_CallbackInfo info) { 142 JSVM_CallbackStruct param; 143 param.data = nullptr; 144 param.callback = CreateInstance; 145 JSVM_Value cons; 146 // 用于在JavaScript中定义一个类 147 JSVM_CALL(OH_JSVM_DefineClass(env, "MyObject", JSVM_AUTO_LENGTH, ¶m, 0, nullptr, &cons)); 148 JSVM_Value instanceValue = nullptr; 149 // 作为class的构造函数调用 150 JSVM_CALL(OH_JSVM_NewInstance(env, cons, 0, nullptr, &instanceValue)); 151 std::string str = ToString(env, instanceValue); 152 OH_LOG_INFO(LOG_APP, "NewInstance:%{public}s", str.c_str()); 153 154 // 作为普通的函数调用 155 JSVM_Value global; 156 JSVM_CALL(OH_JSVM_GetGlobal(env, &global)); 157 JSVM_Value key; 158 JSVM_CALL(OH_JSVM_CreateStringUtf8(env, "Constructor", JSVM_AUTO_LENGTH, &key)); 159 JSVM_CALL(OH_JSVM_SetProperty(env, global, key, cons)); 160 JSVM_Value result; 161 JSVM_CALL(OH_JSVM_CallFunction(env, global, cons, 0, nullptr, &result)); 162 std::string buf = ToString(env, result); 163 OH_LOG_INFO(LOG_APP, "NewInstance:%{public}s", buf.c_str()); 164 return nullptr; 165} 166 167// 注册DefineClass的方法 168JSVM_CallbackStruct param[] = { 169 {.data = nullptr, .callback = DefineClass}, 170}; 171 172static JSVM_CallbackStruct *method = param; 173 174// DefineClass方法别名,供JS调用 175static JSVM_PropertyDescriptor descriptor[] = { 176 {"defineClass", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 177}; 178 179``` 180 181#### 样例JS 182 183const char *srcCallNative = R"JS( 184 defineClass(); 185)JS"; 186 187#### 执行结果 188 189在LOG中输出下面的结果: 190 191Create Instance 192 193NAPI MyObject::New newTarget != nullptr 194 195NewInstance:{"name":"lilei"} 196 197Create Instance 198 199NAPI MyObject::New newTarget == nullptr 200 201NewInstance:{"name":"lilei"} 202 203### OH_JSVM_Wrap 204 205在JavaScript对象中封装原生实例。稍后可以使用OH_JSVM_Unwrap()解包原生实例 206 207### OH_JSVM_Unwrap 208 209解包先前封装在JavaScript对象中的原生实例 210 211### OH_JSVM_RemoveWrap 212 213解包先前封装在JavaScript对象中的原生实例并释放封装 214 215cpp部分代码 216 217```cpp 218// hello.cpp 219#include <string> 220 221// OH_JSVM_GetNewTarget、OH_JSVM_DefineClass、OH_JSVM_Wrap、OH_JSVM_Unwrap、OH_JSVM_RemoveWrap的样例方法 222 223// 自定义类结构体Object 224struct Object { 225 std::string name; 226 int32_t age; 227}; 228 229// 定义一个回调函数 230static void DerefItem(JSVM_Env env, void *data, void *hint) { 231 OH_LOG_INFO(LOG_APP, "JSVM deref_item"); 232 (void)hint; 233} 234 235static JSVM_Value WrapObject(JSVM_Env env, JSVM_CallbackInfo info) { 236 OH_LOG_INFO(LOG_APP, "JSVM wrap"); 237 Object obj; 238 // 设置Object属性 239 obj.name = "lilei"; 240 obj.age = 18; 241 Object *objPointer = &obj; 242 // 获取回调信息中的参数数量和将要被封装的值 243 size_t argc = 1; 244 JSVM_Value toWrap = nullptr; 245 JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, &toWrap, nullptr, nullptr)); 246 // OH_JSVM_Wrap将自定义结构Object进行封装 247 JSVM_CALL(OH_JSVM_Wrap(env, toWrap, reinterpret_cast<void *>(objPointer), DerefItem, NULL, NULL)); 248 Object *data; 249 // OH_JSVM_UnWrap解包先前封装在JavaScript对象中的原生实例 250 JSVM_CALL(OH_JSVM_Unwrap(env, toWrap, reinterpret_cast<void **>(&data))); 251 OH_LOG_INFO(LOG_APP, "JSVM name: %{public}s", data->name.c_str()); 252 OH_LOG_INFO(LOG_APP, "JSVM age: %{public}d", data->age); 253 return nullptr; 254} 255 256static JSVM_Value RemoveWrap(JSVM_Env env, JSVM_CallbackInfo info) { 257 OH_LOG_INFO(LOG_APP, "JSVM removeWrap"); 258 Object obj; 259 // 设置Object属性 260 obj.name = "lilei"; 261 obj.age = 18; 262 Object *objPointer = &obj; 263 // 获取回调信息中的参数数量和将要被封装的值 264 size_t argc = 1; 265 JSVM_Value toWrap = nullptr; 266 JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, &toWrap, nullptr, nullptr)); 267 // 将自定义结构Object封装 268 JSVM_CALL(OH_JSVM_Wrap(env, toWrap, reinterpret_cast<void *>(objPointer), DerefItem, NULL, NULL)); 269 Object *data; 270 // 解包先前封装的object,并移除封装 271 JSVM_CALL(OH_JSVM_RemoveWrap(env, toWrap, reinterpret_cast<void **>(&objPointer))); 272 // 检查是否已被移除 273 JSVM_Status status = OH_JSVM_Unwrap(env, toWrap, reinterpret_cast<void **>(&data)); 274 if (status != JSVM_OK) { 275 OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_RemoveWrap success"); 276 } 277 return nullptr; 278} 279 280// WrapObject、RemoveWrap注册回调 281static JSVM_CallbackStruct param[] = { 282 {.data = nullptr, .callback = WrapObject}, 283 {.data = nullptr, .callback = RemoveWrap}, 284}; 285static JSVM_CallbackStruct *method = param; 286// WrapObject、RemoveWrap方法别名,供JS调用 287static JSVM_PropertyDescriptor descriptor[] = { 288 {"wrapObject", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 289 {"removeWrap", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 290}; 291``` 292 293#### 样例JS 294 295const char *srcCallNative = R"JS( 296 class Obj {}; 297 wrapObject(new Obj()); 298 removeWrap(new Obj()); 299)JS"; 300 301#### 执行结果 302 303在LOG中输出下面的结果: 304 305JSVM wrap 306 307JSVM name: lilei 308 309JSVM age: 18 310 311JSVM removeWrap 312 313JSVM OH_JSVM_RemoveWrap success 314 315JSVM deref_item 316 317### OH_JSVM_DefineClassWithOptions 318**Note:** 传入的父类class必须是通过OH_JSVM_DefineClass系列接口创建出来的,不然会被视为无效参数,返回JSVM_INVALID_ARG错误码。 319目前支持以下的DefineClassOptions: 320- JSVM_DEFINE_CLASS_NORMAL: 按正常模式创建Class。默认缺省状态为JSVM_DEFINE_CLASS_NORMAL状态。 321- JSVM_DEFINE_CLASS_WITH_COUNT: 为所创建的Class预留interfield槽位。 322- JSVM_DEFINE_CLASS_WITH_PROPERTY_HANDLER: 为所创建的Class设置监听拦截属性以及设置作为函数调用时回调函数。 323#### cpp代码 324```c++ 325static JSVM_PropertyHandlerConfigurationStruct propertyCfg{ 326 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr 327}; 328 329static bool g_call_as_function_flag = false; 330static bool g_set_named_property_flag = false; 331static bool g_call_as_constructor_flag = false; 332static bool g_properties_flag = false; 333 334static JSVM_Value SetNamedPropertyCbInfo2(JSVM_Env env, JSVM_Value name, JSVM_Value property, JSVM_Value thisArg, 335 JSVM_Value data) 336{ 337 g_set_named_property_flag = true; 338 return property; 339} 340 341static JSVM_Value Add(JSVM_Env env, JSVM_CallbackInfo info) { 342 g_properties_flag = true; 343 size_t argc = 2; 344 JSVM_Value args[2]; 345 OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL); 346 double num1, num2; 347 OH_JSVM_GetValueDouble(env, args[0], &num1); 348 OH_JSVM_GetValueDouble(env, args[1], &num2); 349 JSVM_Value sum = nullptr; 350 OH_JSVM_CreateDouble(env, num1 + num2, &sum); 351 return sum; 352} 353 354std::string ToString(JSVM_Env jsvm_env, JSVM_Value val) 355{ 356 JSVM_Value js_string; 357 OH_JSVM_CoerceToString(jsvm_env, val, &js_string); 358 size_t length = 0; 359 OH_JSVM_GetValueStringUtf8(jsvm_env, js_string, NULL, 0, &length); 360 size_t capacity = length + 1; 361 char *buffer = new char[capacity]; 362 size_t copy_length = 0; 363 OH_JSVM_GetValueStringUtf8(jsvm_env, js_string, buffer, capacity, ©_length); 364 std::string str(buffer); 365 delete[] buffer; 366 return str; 367} 368 369JSVM_Value Run(JSVM_Env env, const char *s) 370{ 371 // 1. 将const char*转换成JS_String。 372 JSVM_Value str; 373 JSVM_CALL(OH_JSVM_CreateStringUtf8(env, s, JSVM_AUTO_LENGTH, &str)); 374 // 2. 将JS_String转换成JS_Script。 375 JSVM_Script script; 376 OH_JSVM_CompileScript(jsvm_env, str, nullptr, JSVM_AUTO_LENGTH, false, nullptr, &script); 377 // 3. 执行JS_Script。 378 JSVM_Value result; 379 OH_JSVM_RunScript(jsvm_env, script, &result); 380 return result; 381} 382 383static JSVM_Value TestDefineClassWithOptions(JSVM_Env env, JSVM_CallbackInfo info) 384{ 385 g_call_as_function_flag = false; 386 g_set_named_property_flag = false; 387 g_call_as_constructor_flag = false; 388 g_properties_flag = false; 389 // 1. Define parent-class. 390 JSVM_Value parentClass = nullptr; 391 JSVM_CallbackStruct parentClassConstructor; 392 parentClassConstructor.data = nullptr; 393 parentClassConstructor.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { 394 JSVM_Value thisVar = nullptr; 395 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr); 396 return thisVar; 397 }; 398 JSVM_Value fooVal = Str(env, "bar"); 399 JSVM_PropertyDescriptor des[2]; 400 des[0] = { 401 .utf8name = "foo", 402 .value = fooVal, 403 }; 404 JSVM_CallbackStruct parentProperties[] = { 405 {.callback = Add, .data = nullptr}, 406 }; 407 des[1] = { 408 .utf8name = "add", 409 .method = &parentProperties[0], 410 }; 411 JSVM_DefineClassOptions options[1]; 412 options[0].id = JSVM_DEFINE_CLASS_WITH_COUNT; 413 options[0].content.num = 3; 414 JSVM_CALL(OH_JSVM_DefineClassWithOptions(env, "parentClass", JSVM_AUTO_LENGTH, &parentClassConstructor, 2, des, 415 nullptr, 1, options, &parentClass)); 416 417 // 2. Define sub-class. 418 JSVM_Value subClass = nullptr; 419 JSVM_CallbackStruct subClassConstructor; 420 subClassConstructor.data = nullptr; 421 subClassConstructor.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { 422 JSVM_Value thisVar = nullptr; 423 g_call_as_constructor_flag = true; 424 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr); 425 return thisVar; 426 }; 427 JSVM_DefineClassOptions subOptions[2]; 428 JSVM_CallbackStruct callAsFuncParam; 429 callAsFuncParam.data = nullptr; 430 callAsFuncParam.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { 431 JSVM_Value thisVar = nullptr; 432 g_call_as_function_flag = true; 433 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr); 434 return thisVar; 435 }; 436 propertyCfg.genericNamedPropertySetterCallback = SetNamedPropertyCbInfo2; 437 JSVM_PropertyHandler propertyHandler = { 438 .propertyHandlerCfg = &propertyCfg, 439 .callAsFunctionCallback = &callAsFuncParam, 440 }; 441 subOptions[0].id = JSVM_DEFINE_CLASS_WITH_COUNT; 442 subOptions[0].content.num = 4; 443 subOptions[1].id = JSVM_DEFINE_CLASS_WITH_PROPERTY_HANDLER; 444 subOptions[1].content.ptr = &propertyHandler; 445 JSVM_CALL(OH_JSVM_DefineClassWithOptions(env, "subClass", JSVM_AUTO_LENGTH, &subClassConstructor, 0, nullptr, 446 parentClass, 2, subOptions, &subClass)); 447 // 3. Verify the validity of 'constructor'. 448 JSVM_Value subInstance; 449 JSVM_CALL(OH_JSVM_NewInstance(env, subClass, 0, nullptr, &subInstance)); 450 451 JSVM_Value globalVal; 452 OH_JSVM_GetGlobal(env, &globalVal); 453 OH_JSVM_SetNamedProperty(env, globalVal, "obj", subInstance); 454 455 // 4. Verify the validity of 'parentClass'. 456 JSVM_Value subRes = nullptr; 457 JSVM_CALL(OH_JSVM_GetNamedProperty(env, subInstance, "foo", &subRes)); 458 if (ToString(env, subRes).compare("bar") != 0) { 459 OH_LOG_ERROR(LOG_APP, "Run OH_JSVM_DefineClassWithOptions: Failed"); 460 } 461 // 5. Verify the validity of 'properties'. 462 Run(env, "obj.add(3, 4);"); 463 // 6. Verify the validity of 'options'. 464 Run(env, "obj()"); 465 Run(env, "obj.x = 123;"); 466 if (g_call_as_function_flag == true && 467 g_set_named_property_flag == true && 468 g_call_as_constructor_flag == true && 469 g_properties_flag == true) { 470 OH_LOG_INFO(LOG_APP, "Run OH_JSVM_DefineClassWithOptions: Success"); 471 } else { 472 OH_LOG_ERROR(LOG_APP, "Run OH_JSVM_DefineClassWithOptions: Failed"); 473 } 474 return nullptr; 475} 476``` 477 478#### 样例JS 479 480const char *srcCallNative = R"JS( 481 class Obj {}; 482 wrapObject(new Obj()); 483 removeWrap(new Obj()); 484)JS"; 485 486#### 执行结果 487 488在LOG中输出下面的结果: 489 490JSVM wrap 491 492JSVM name: lilei 493 494JSVM age: 18 495 496JSVM removeWrap 497 498JSVM OH_JSVM_RemoveWrap success 499 500JSVM deref_item 501 502### OH_JSVM_DefineClassWithOptions 503**Note:** 传入的父类class必须是通过OH_JSVM_DefineClass系列接口创建出来的,不然会被视为无效参数,返回JSVM_INVALID_ARG错误码。 504目前支持以下的DefineClassOptions: 505- JSVM_DEFINE_CLASS_NORMAL: 按正常模式创建Class。默认缺省状态为JSVM_DEFINE_CLASS_NORMAL状态。 506- JSVM_DEFINE_CLASS_WITH_COUNT: 为所创建的Class预留interfield槽位。 507- JSVM_DEFINE_CLASS_WITH_PROPERTY_HANDLER: 为所创建的Class设置监听拦截属性以及设置作为函数调用时回调函数 508#### cpp代码 509```c++ 510static JSVM_PropertyHandlerConfigurationStruct propertyCfg{ 511 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr 512}; 513 514static bool g_call_as_function_flag = false; 515static bool g_set_named_property_flag = false; 516static bool g_call_as_constructor_flag = false; 517static bool g_properties_flag = false; 518 519static JSVM_Value SetNamedPropertyCbInfo2(JSVM_Env env, JSVM_Value name, JSVM_Value property, JSVM_Value thisArg, 520 JSVM_Value data) 521{ 522 g_set_named_property_flag = true; 523 return property; 524} 525 526static JSVM_Value Add(JSVM_Env env, JSVM_CallbackInfo info) { 527 g_properties_flag = true; 528 size_t argc = 2; 529 JSVM_Value args[2]; 530 OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL); 531 double num1, num2; 532 OH_JSVM_GetValueDouble(env, args[0], &num1); 533 OH_JSVM_GetValueDouble(env, args[1], &num2); 534 JSVM_Value sum = nullptr; 535 OH_JSVM_CreateDouble(env, num1 + num2, &sum); 536 return sum; 537} 538 539std::string ToString(JSVM_Env jsvm_env, JSVM_Value val) 540{ 541 JSVM_Value js_string; 542 OH_JSVM_CoerceToString(jsvm_env, val, &js_string); 543 size_t length = 0; 544 OH_JSVM_GetValueStringUtf8(jsvm_env, js_string, NULL, 0, &length); 545 size_t capacity = length + 1; 546 char *buffer = new char[capacity]; 547 size_t copy_length = 0; 548 OH_JSVM_GetValueStringUtf8(jsvm_env, js_string, buffer, capacity, ©_length); 549 std::string str(buffer); 550 delete[] buffer; 551 return str; 552} 553 554JSVM_Value Run(JSVM_Env env, const char *s) 555{ 556 // 1. 将const char*转换成JS_String。 557 JSVM_Value str; 558 JSVM_CALL(OH_JSVM_CreateStringUtf8(env, s, JSVM_AUTO_LENGTH, &str)); 559 // 2. 将JS_String转换成JS_Script。 560 JSVM_Script script; 561 OH_JSVM_CompileScript(jsvm_env, str, nullptr, JSVM_AUTO_LENGTH, false, nullptr, &script); 562 // 3. 执行JS_Script。 563 JSVM_Value result; 564 OH_JSVM_RunScript(jsvm_env, script, &result); 565 return result; 566} 567 568static JSVM_Value TestDefineClassWithOptions(JSVM_Env env, JSVM_CallbackInfo info) 569{ 570 g_call_as_function_flag = false; 571 g_set_named_property_flag = false; 572 g_call_as_constructor_flag = false; 573 g_properties_flag = false; 574 // 1. Define parent-class. 575 JSVM_Value parentClass = nullptr; 576 JSVM_CallbackStruct parentClassConstructor; 577 parentClassConstructor.data = nullptr; 578 parentClassConstructor.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { 579 JSVM_Value thisVar = nullptr; 580 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr); 581 return thisVar; 582 }; 583 JSVM_Value fooVal = Str(env, "bar"); 584 JSVM_PropertyDescriptor des[2]; 585 des[0] = { 586 .utf8name = "foo", 587 .value = fooVal, 588 }; 589 JSVM_CallbackStruct parentProperties[] = { 590 {.callback = Add, .data = nullptr}, 591 }; 592 des[1] = { 593 .utf8name = "add", 594 .method = &parentProperties[0], 595 }; 596 JSVM_DefineClassOptions options[1]; 597 options[0].id = JSVM_DEFINE_CLASS_WITH_COUNT; 598 options[0].content.num = 3; 599 JSVM_CALL(OH_JSVM_DefineClassWithOptions(env, "parentClass", JSVM_AUTO_LENGTH, &parentClassConstructor, 2, des, 600 nullptr, 1, options, &parentClass)); 601 602 // 2. Define sub-class. 603 JSVM_Value subClass = nullptr; 604 JSVM_CallbackStruct subClassConstructor; 605 subClassConstructor.data = nullptr; 606 subClassConstructor.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { 607 JSVM_Value thisVar = nullptr; 608 g_call_as_constructor_flag = true; 609 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr); 610 return thisVar; 611 }; 612 JSVM_DefineClassOptions subOptions[2]; 613 JSVM_CallbackStruct callAsFuncParam; 614 callAsFuncParam.data = nullptr; 615 callAsFuncParam.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { 616 JSVM_Value thisVar = nullptr; 617 g_call_as_function_flag = true; 618 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr); 619 return thisVar; 620 }; 621 propertyCfg.genericNamedPropertySetterCallback = SetNamedPropertyCbInfo2; 622 JSVM_PropertyHandler propertyHandler = { 623 .propertyHandlerCfg = &propertyCfg, 624 .callAsFunctionCallback = &callAsFuncParam, 625 }; 626 subOptions[0].id = JSVM_DEFINE_CLASS_WITH_COUNT; 627 subOptions[0].content.num = 4; 628 subOptions[1].id = JSVM_DEFINE_CLASS_WITH_PROPERTY_HANDLER; 629 subOptions[1].content.ptr = &propertyHandler; 630 JSVM_CALL(OH_JSVM_DefineClassWithOptions(env, "subClass", JSVM_AUTO_LENGTH, &subClassConstructor, 0, nullptr, 631 parentClass, 2, subOptions, &subClass)); 632 // 3. Verify the validity of 'constructor'. 633 JSVM_Value subInstance; 634 JSVM_CALL(OH_JSVM_NewInstance(env, subClass, 0, nullptr, &subInstance)); 635 636 JSVM_Value globalVal; 637 OH_JSVM_GetGlobal(env, &globalVal); 638 OH_JSVM_SetNamedProperty(env, globalVal, "obj", subInstance); 639 640 // 4. Verify the validity of 'parentClass'. 641 JSVM_Value subRes = nullptr; 642 JSVM_CALL(OH_JSVM_GetNamedProperty(env, subInstance, "foo", &subRes)); 643 if (ToString(env, subRes).compare("bar") != 0) { 644 OH_LOG_ERROR(LOG_APP, "Run OH_JSVM_DefineClassWithOptions: Failed"); 645 } 646 // 5. Verify the validity of 'properties'. 647 Run(env, "obj.add(3, 4);"); 648 // 6. Verify the validity of 'options'. 649 Run(env, "obj()"); 650 Run(env, "obj.x = 123;"); 651 if (g_call_as_function_flag == true && 652 g_set_named_property_flag == true && 653 g_call_as_constructor_flag == true && 654 g_properties_flag == true) { 655 OH_LOG_INFO(LOG_APP, "Run OH_JSVM_DefineClassWithOptions: Success"); 656 } else { 657 OH_LOG_ERROR(LOG_APP, "Run OH_JSVM_DefineClassWithOptions: Failed"); 658 } 659 JSVM_Value checked; 660 OH_JSVM_GetBoolean(env, true, &checked); 661 return checked; 662} 663 664static JSVM_CallbackStruct param[] = { 665 {.data = nullptr, .callback = TestDefineClassWithOptions}, 666}; 667static JSVM_CallbackStruct *method = param; 668 669static JSVM_PropertyDescriptor descriptor[] = { 670 {"testDefineClassWithOptions", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 671}; 672 673``` 674#### 样例JS 675 676const char *srcCallNative = R"JS(testDefineClassWithOptions();)JS"; 677#### 执行结果 678 679在LOG中输出下面的结果: 680Run OH_JSVM_DefineClassWithOptions: Success 681