1# Working with Classes Using JSVM-API 2 3## Introduction 4 5JSVM-API provides APIs for managing JavaScript (JS) classes, for example, defining a JS class and creating a JS instance. 6 7## Basic Concepts 8 9To begin with, it is important to understand the following basic concepts: 10 11- Class: a template used to create an object. It provides a way to define object properties and methods in a structured manner. Classes in JavaScript are based on prototypes. Moreover, unique syntax and semantics of classes are introduced. 12- Instance: an object created from a class. A class defines the structure and behavior of an object, and an instance is a specific representation of a class. Instantiating a class allows access to the properties and methods defined in the class. Each instance has its own property values. 13 14## Available APIs 15 16| API | Description | 17| ------------------- | ---------------------------------- | 18| OH_JSVM_NewInstance | Creates an instance from the given constructor.| 19| OH_JSVM_GetNewTarget | Obtains **new.target** of the constructor call.| 20| OH_JSVM_DefineClass | Defines a JS class and associated functions within a C/C++ addon. It allows you to define a constructor, methods, and properties that can be accessed from JS.| 21| OH_JSVM_Wrap | Wraps a native instance in a JS object. You can use **OH_JSVM_Unwrap()** to retrieve the native instance later.| 22| OH_JSVM_Unwrap | Unwraps a native instance from a JS object.| 23| OH_JSVM_RemoveWrap | Removes the wrapping after the native instance is unwrapped from a JS object.| 24 25## Example 26 27If you are just starting out with JSVM-API, see [JSVM-API Development Process](use-jsvm-process.md). The following only demonstrates the C++ and ArkTS code involved in the class-related APIs. 28 29### OH_JSVM_NewInstance 30 31Use **OH_JSVM_NewInstance** to create an instance from the given constructor. 32 33CPP code: 34 35```cpp 36// hello.cpp 37#include "napi/native_api.h" 38#include "ark_runtime/jsvm.h" 39#include <hilog/log.h> 40Create an instance from the given constructor. 41// Register the NewInstance callback. 42static JSVM_CallbackStruct param[] = { 43 {.data = nullptr, .callback = NewInstance}, 44}; 45static JSVM_CallbackStruct *method = param; 46// Set a property descriptor named newInstance and associate it with a callback. This allows the NewInstance callback to be called from JS. 47static JSVM_PropertyDescriptor descriptor[] = { 48 {"newInstance", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 49}; 50// Define OH_JSVM_NewInstance. 51static JSVM_Value NewInstance(JSVM_Env env, JSVM_CallbackInfo info) { 52 // Obtain the two parameters passed from JS. 53 size_t argc = 2; 54 JSVM_Value args[2] = {nullptr}; 55 OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr); 56 // Call OH_JSVM_NewInstance to create an instance and return the instance created. 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 code: 69 70```ts 71import hilog from '@ohos.hilog' 72// Import the native APIs. 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 90Use **OH_JSVM_GetNewTarget** to obtain **new.target** of a constructor. In JS, **new.target** is a meta property used to determine whether a constructor was called using the **new** operator. 91 92### OH_JSVM_DefineClass 93 94Use **OH_JSVM_DefineClass** to define a JS class and associated functions within a C/C++ addon. It allows you to define a constructor, methods, and properties that can be accessed from JS. 95 96CPP code: 97 98```cpp 99// hello.cpp 100#include "napi/native_api.h" 101#include "ark_runtime/jsvm.h" 102#include <hilog/log.h> 103// Define a class struct. 104struct DefineObject { 105 std::string name; 106 int32_t age; 107 JSVM_Ref wrapper_; 108}; 109static thread_local JSVM_Ref g_ref = nullptr; 110// Create an instance. 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 // Invoked as the constructor `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// Obtain the data in the encapsulated C++ struct. 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// Encapsulate the struct in 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 165Modify the **RunJsVm** method defined in [JSVM-API Development Process](use-jsvm-process.md) as follows: 166 167```cpp 168 // hello.cpp 169 // Change the reserved code in defineClass() as follows: 170 if (strcmp(sourceCodeStr.c_str(), "defineClass") == 0) { 171 JSVM_Value obj; 172 DefineClass(env, obj); 173 nResult = GetObj(nEnv); 174 } 175``` 176 177ArkTS code: 178 179```ts 180import hilog from '@ohos.hilog' 181// Import the native APIs. 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 194Use **OH_JSVM_Wrap** to wrap a native instance in a JS object. You can use **OH_JSVM_Unwrap()** to retrieve the native instance later. 195 196### OH_JSVM_Unwrap 197 198Use **OH_JSVM_Unwrap** to unwrap a native instance from a JS object. 199 200### OH_JSVM_RemoveWrap 201 202Use **OH_JSVM_RemoveWrap** to retrieve a native instance previously wrapped in a JS object and remove the wrapping. 203 204CPP code: 205 206```cpp 207// hello.cpp 208#include "napi/native_api.h" 209#include "ark_runtime/jsvm.h" 210#include <hilog/log.h> 211// Register the WrapObject and RemoveWrap callbacks. 212static JSVM_CallbackStruct param[] = { 213 {.data = nullptr, .callback = WrapObject}, 214 {.data = nullptr, .callback = RemoveWrap}, 215}; 216static JSVM_CallbackStruct *method = param; 217// Set property descriptors named wrapObject and removeWrap and associate them with a callback each. This allows the WrapObject and RemoveWrap callbacks to be called from 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// Define OH_JSVM_GetNewTarget, OH_JSVM_DefineClass, OH_JSVM_Wrap, OH_JSVM_Unwrap, and OH_JSVM_RemoveWrap. 223// Check whether the deref_item function is called. 224static bool deref_item_called = false; 225 226// Define the struct Object. 227struct Object { 228 std::string name; 229 int32_t age; 230}; 231struct Object *obj = new struct Object(); 232 233// Define a callback function. 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 // Set a property for the object. 242 obj->name = "lilei"; 243 obj->age = 18; 244 // Obtain the number of parameters in the callback and the values to be wrapped. 245 size_t argc = 1; 246 JSVM_Value toWrap = nullptr; 247 OH_JSVM_GetCbInfo(env, info, &argc, &toWrap, nullptr, nullptr); 248 // Wrap the Object struct. 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 // Retrieve the previously wrapped object and remove the wrapping. 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 code: 278 279```ts 280import hilog from '@ohos.hilog' 281// Import the native APIs. 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