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.target113    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, &param, 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, &copy_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, &copy_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