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 | 使用OH_JSVM_Wrap()检索先前封装在JavaScript对象中的原生实例| 23| OH_JSVM_RemoveWrap | 检索先前封装在JavaScript对象中的原生实例并移除封装| 24 25## 使用示例 26 27JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++及ArkTS相关代码进行展示。 28 29### OH_JSVM_NewInstance 30 31通过给定的构造函数,构建一个实例。 32 33cpp部分代码 34 35```cpp 36// hello.cpp 37#include "napi/native_api.h" 38#include "ark_runtime/jsvm.h" 39#include <hilog/log.h> 40通过给定的构造函数,构建一个实例。 41// NewInstance注册回调 42static JSVM_CallbackStruct param[] = { 43 {.data = nullptr, .callback = NewInstance}, 44}; 45static JSVM_CallbackStruct *method = param; 46// NewInstance方法别名,供JS调用 47static JSVM_PropertyDescriptor descriptor[] = { 48 {"newInstance", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 49}; 50// OH_JSVM_NewInstance的样例方法 51static JSVM_Value NewInstance(JSVM_Env env, JSVM_CallbackInfo info) { 52 // 获取js侧传入的两个参数 53 size_t argc = 2; 54 JSVM_Value args[2] = {nullptr}; 55 OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr); 56 // 调用OH_JSVM_NewInstance接口,实例化一个对象,将这个对象返回 57 JSVM_Value result = nullptr; 58 JSVM_Status status = OH_JSVM_NewInstance(env, args[0], 1, &args[1], &result); 59 if (status != JSVM_OK) { 60 OH_LOG_ERROR(LOG_APP, "JSVM API TEST RESULT: PASS"); 61 } else { 62 OH_LOG_INFO(LOG_APP, "JSVM API TEST RESULT: PASS"); 63 } 64 return result; 65} 66``` 67 68ArkTS侧示例代码 69 70```ts 71import hilog from '@ohos.hilog' 72// 通过import的方式,引入Native能力。 73import napitest from 'libentry.so' 74let script: string = ` 75 function Fruit(name) { 76 this.name = name; 77 } 78 newInstance(Fruit, "apple"); 79 `; 80try { 81 let result = napitest.runJsVm(script.toString()); 82 hilog.info(0x0000, 'JSVM', 'NewInstance:%{public}s', result); 83} catch (error) { 84 hilog.error(0x0000, 'JSVM', 'NewInstance:%{public}s', error.message); 85} 86``` 87 88### OH_JSVM_GetNewTarget 89 90用于获取构造函数的new.target值。在JavaScript中,new.target是一个特殊的元属性,用于在构造函数中判断是否通过new关键字调用了该构造函数。 91 92### OH_JSVM_DefineClass 93 94用于在JavaScript中定义一个类,并与对应的C类进行封装和交互。它提供了创建类的构造函数、定义属性和方法的能力,以及在C和JavaScript之间进行数据交互的支持 95 96cpp部分代码 97 98```cpp 99// hello.cpp 100#include "napi/native_api.h" 101#include "ark_runtime/jsvm.h" 102#include <hilog/log.h> 103// 自定义类结构体 104struct DefineObject { 105 std::string name; 106 int32_t age; 107 JSVM_Ref wrapper_; 108}; 109static thread_local JSVM_Ref g_ref = nullptr; 110// 创建实例 111struct DefineObject *defineObject = new struct DefineObject(); 112JSVM_Value New(JSVM_Env env, JSVM_CallbackInfo info) { 113 JSVM_Value newTarget; 114 OH_JSVM_GetNewTarget(env, info, &newTarget); 115 if (newTarget != nullptr) { 116 OH_LOG_INFO(LOG_APP, "NAPI MyObject::New newTarget != nullptr"); 117 // 使用`new MyObject(...)`调用方式 118 size_t argc = 1; 119 JSVM_Value args[1]; 120 JSVM_Value jsThis; 121 OH_JSVM_GetCbInfo(env, info, &argc, args, &jsThis, nullptr); 122 double value = 0.0; 123 JSVM_ValueType valuetype; 124 OH_JSVM_Typeof(env, args[0], &valuetype); 125 if (valuetype != JSVM_UNDEFINED) { 126 OH_JSVM_GetValueDouble(env, args[0], &value); 127 } 128 defineObject->name = "lilei"; 129 defineObject->age = 18; 130 return nullptr; 131 } else { 132 OH_LOG_INFO(LOG_APP, "NAPI MyObject::New newTarget == nullptr"); 133 size_t argc = 1; 134 JSVM_Value args[1]; 135 (OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr)); 136 JSVM_Value cons; 137 (OH_JSVM_GetReferenceValue(env, g_ref, &cons)); 138 JSVM_Value instance; 139 (OH_JSVM_NewInstance(env, cons, argc, args, &instance)); 140 return instance; 141 } 142} 143 144// 获取封装后的c++自定义结构中的数据方法 145napi_value GetObj(napi_env env) { 146 std::string str = "{\"name\": \"" + defineObject->name + "\",\"age\": " + std::to_string(defineObject->age) + "}"; 147 napi_value jsResult; 148 napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &jsResult); 149 return jsResult; 150} 151 152// 封装c++中的自定义数据结构 153JSVM_Value DefineClass(JSVM_Env env, JSVM_Value exports) { 154 JSVM_CallbackStruct param1; 155 param1.data = nullptr; 156 param1.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { return New(env, info); }; 157 JSVM_Value cons; 158 OH_JSVM_DefineClass(env, "MyObject", JSVM_AUTO_LENGTH, ¶m1, 0, nullptr, &cons); 159 JSVM_Value instanceValue = nullptr; 160 OH_JSVM_NewInstance(env, cons, 0, nullptr, &instanceValue); 161 return nullptr; 162} 163``` 164 165需要将[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md)中的RunJsVm方法改动如下: 166 167```cpp 168 // hello.cpp 169 // 将JSVM开发流程文档中defineClass方法的预留位置的代码更改为如下内容 170 if (strcmp(sourceCodeStr.c_str(), "defineClass") == 0) { 171 JSVM_Value obj; 172 DefineClass(env, obj); 173 nResult = GetObj(nEnv); 174 } 175``` 176 177ArkTS侧示例代码 178 179```ts 180import hilog from '@ohos.hilog' 181// 通过import的方式,引入Native能力。 182import napitest from 'libentry.so' 183// test defineclass 184try { 185 let result = napitest.runJsVm("defineClass"); 186 hilog.info(0x0000, 'testJSVM', 'Test JSVM defineclass:%{public}s', JSON.stringify(result)); 187} catch (error) { 188 hilog.error(0x0000, 'testJSVM', 'Test JSVM AssertEqual error: %{public}s', error); 189} 190``` 191 192### OH_JSVM_Wrap 193 194在JavaScript对象中封装原生实例。稍后可以使用OH_JSVM_Unwrap()检索原生实例 195 196### OH_JSVM_Unwrap 197 198使用OH_JSVM_Wrap()检索先前封装在JavaScript对象中的原生实例 199 200### OH_JSVM_RemoveWrap 201 202检索先前封装在JavaScript对象中的原生实例并移除封装 203 204cpp部分代码 205 206```cpp 207// hello.cpp 208#include "napi/native_api.h" 209#include "ark_runtime/jsvm.h" 210#include <hilog/log.h> 211// WrapObject、RemoveWrap注册回调 212static JSVM_CallbackStruct param[] = { 213 {.data = nullptr, .callback = WrapObject}, 214 {.data = nullptr, .callback = RemoveWrap}, 215}; 216static JSVM_CallbackStruct *method = param; 217// WrapObject、RemoveWrap方法别名,供JS调用 218static JSVM_PropertyDescriptor descriptor[] = { 219 {"wrapObject", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 220 {"removeWrap", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT} 221}; 222// OH_JSVM_GetNewTarget、OH_JSVM_DefineClass、OH_JSVM_Wrap、OH_JSVM_Unwrap、OH_JSVM_RemoveWrap的样例方法 223// 表示是否调用了deref_item函数 224static bool deref_item_called = false; 225 226// 自定义类结构体Object 227struct Object { 228 std::string name; 229 int32_t age; 230}; 231struct Object *obj = new struct Object(); 232 233// 定义一个回调函数 234static void DerekItem(JSVM_Env env, void *data, void *hint) { 235 OH_LOG_INFO(LOG_APP, "JSVM deref_item"); 236 (void)hint; 237} 238 239static JSVM_Value WrapObject(JSVM_Env env, JSVM_CallbackInfo info) { 240 OH_LOG_INFO(LOG_APP, "JSVM wrap"); 241 // 设置Object属性 242 obj->name = "lilei"; 243 obj->age = 18; 244 // 获取回调信息中的参数数量和将要被封装的值 245 size_t argc = 1; 246 JSVM_Value toWrap = nullptr; 247 OH_JSVM_GetCbInfo(env, info, &argc, &toWrap, nullptr, nullptr); 248 // 将自定义结构Object封装 249 OH_JSVM_Wrap(env, toWrap, reinterpret_cast<void *>(obj), DerekItem, NULL, NULL); 250 struct Object *data; 251 struct Object *data1; 252 OH_JSVM_Unwrap(env, toWrap, reinterpret_cast<void **>(&data)); 253 OH_LOG_INFO(LOG_APP, "JSVM name: %{public}s", data->name.c_str()); 254 OH_LOG_INFO(LOG_APP, "JSVM age: %{public}d", data->age); 255 //检索先前封装的object,并移除封装 256 OH_JSVM_RemoveWrap(env, toWrap, reinterpret_cast<void **>(&obj)); 257 JSVM_Status status = OH_JSVM_Unwrap(env, toWrap, reinterpret_cast<void **>(&data1)); 258 if (status != JSVM_OK) { 259 OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_RemoveWrap success"); 260 } 261 JSVM_Value checked; 262 OH_JSVM_GetBoolean(env, true, &checked); 263 return checked; 264} 265 266static JSVM_Value RemoveWrap(JSVM_Env env, JSVM_CallbackInfo info) { 267 OH_LOG_INFO(LOG_APP, "JSVM removeWrap"); 268 size_t argc = 1; 269 JSVM_Value wrapped = nullptr; 270 void *data; 271 OH_JSVM_GetCbInfo(env, info, &argc, &wrapped, nullptr, nullptr); 272 OH_JSVM_RemoveWrap(env, wrapped, &data); 273 return nullptr; 274} 275``` 276 277ArkTS侧示例代码 278 279```ts 280import hilog from '@ohos.hilog' 281// 通过import的方式,引入Native能力。 282import napitest from 'libentry.so' 283// wrapObject 284class Obj {} 285let obj: Obj = `{}`; 286let script: string = ` 287 wrapObject(${obj}); 288 `; 289try { 290 let result = napitest.runJsVm(script); 291 hilog.info(0x0000, 'JSVM', 'WrapObject:%{public}s', result); 292} catch (error) { 293 hilog.error(0x0000, 'JSVM', 'WrapObject:%{public}s', error.message); 294} 295 296// removeWrap 297class Obj {} 298let obj: Obj = `{}`; 299let script: string = ` 300 removeWrap(${obj}); 301 `; 302try { 303 let result = napitest.runJsVm(script); 304 hilog.info(0x0000, 'JSVM', 'RemoveWrap:%{public}s', result); 305} catch (error) { 306 hilog.error(0x0000, 'JSVM', 'RemoveWrap:%{public}s', error.message); 307} 308``` 309