1# Working with Objects Using Node-API 2 3## Overview 4 5Node-API provides APIs for basic ArkTS object operations, including creating an object, obtaining the prototype of an object, freezing or sealing an object, and checking the object type. You can use these APIs to manage ArkTS objects. 6 7## Basic Concepts 8 9You may need to define and operate objects when using Node-API in development. For example, define an API with an object as an input parameter, perform operations on the object, and have a result object returned. In this process, you need to ensure that the API definition is clear and compatible with the properties and methods of the object. 10 11- API: defines the interaction protocol between components. An API includes input parameters, output result, and possible error handling. By calling APIs, components can interact and exchange data with each other without knowing the internal implementation details. 12- Object: a composite data type that allows values of different types to be stored as an independent entity in ArkTS. An object is a collection of properties and methods. A property is a value associated with an object, and a method is an operation that the object can perform. 13 14## Available APIs 15 16The following table lists the APIs for operating and managing ArkTS objects. 17| API| Description| 18| -------- | -------- | 19| napi_get_prototype | Obtains the prototype of an ArkTS object. You can use this API to obtain the prototype object in C/C++.| 20| napi_create_object | Creates a default ArkTS object.| 21| napi_object_freeze | Freezes an ArkTS object. Once an object is frozen, its properties are immutable.| 22| napi_object_seal | Seals an ArkTS object. Once an object is sealed, its properties cannot be added or deleted, but property values can be modified.| 23| napi_typeof | Obtains the type of an ArkTS value.| 24| napi_instanceof | Checks whether an ArkTS object is an instance of the specified constructor.| 25| napi_type_tag_object | Associates the value of a tag pointer with an ArkTS object.| 26| napi_check_object_type_tag | Checks whether a tag pointer is associated with a ArkTS object.| 27| napi_create_symbol | Creates an ArkTS **Symbol** object.| 28| napi_create_external | Creates an ArkTS external object, which can be used to pass custom data structs or objects in C/C++ to ArkTS so that it can be accessible from ArkTS.| 29| napi_get_value_external | Obtains the ArkTS data from the external object created by **napi_create_external**. This API can be used to pass data between ArkTS and C/C++.| 30 31With these APIs, you can easily create and manipulate ArkTS objects in C/C++. 32 33## Example 34 35If you are just starting out with Node-API, see [Node-API Development Process](use-napi-process.md). The following demonstrates only the C++ and ArkTS code related to object management. 36 37### napi_get_prototype 38 39Use **napi_get_prototype** to obtain the prototype of an ArkTS object. 40 41CPP code: 42 43```cpp 44#include "napi/native_api.h" 45 46static napi_value GetPrototype(napi_env env, napi_callback_info info) 47{ 48 // Obtain and parse input parameters. 49 size_t argc = 1; 50 napi_value args[1] = {nullptr}; 51 napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); 52 napi_value result = nullptr; 53 // Obtain the prototype object of this object and return the prototype object obtained to the variable result of the napi_value type. 54 napi_get_prototype(env, args[0], &result); 55 return result; 56} 57``` 58 59API declaration: 60 61```ts 62// index.d.ts 63export const getPrototype: (object: Object) => Object; 64``` 65 66ArkTS code: 67 68```ts 69import hilog from '@ohos.hilog' 70import testNapi from 'libentry.so' 71// Define a class. 72class Person { 73 // Property. 74 name: string; 75 age: number; 76 // Constructor. 77 constructor(name: string, age: number) { 78 this.name = name; 79 this.age = age; 80 } 81} 82// Create a class instance. 83const person = new Person('Alice', 30); 84// Pass in an instance object and obtain the prototype of the object. 85let applePrototype = testNapi.getPrototype(person); 86// Check whether the prototype obtained by testNapi.getPrototype() is an Apple prototype. 87// ArkTS does not have the prototype concept in DevEco Studio 4.1 and later. When you perform prototype-related operations, 'Prototype assignment is not supported (arkts-no-prototype-assignment)' will be displayed. Therefore, you need to run the following code in a TS file: 88if (applePrototype === Person.prototype) { 89 hilog.info(0x0000, 'Node-API', 'get_prototype_success'); 90} else { 91 hilog.info(0x0000, 'Node-API', 'get_prototype_fail'); 92} 93``` 94 95### napi_create_object 96 97Use **napi_create_object** to create an empty ArkTS object. 98 99CPP code: 100 101```cpp 102#include "napi/native_api.h" 103 104napi_value NewObject(napi_env env, napi_callback_info info) 105{ 106 napi_value object = nullptr; 107 // Create an empty object. 108 napi_create_object(env, &object); 109 // Set the object property. 110 napi_value name = nullptr; 111 // Set the property name to "name". 112 napi_create_string_utf8(env, "name", NAPI_AUTO_LENGTH, &name); 113 napi_value value = nullptr; 114 // Set the property value to "Hello from N-API!" 115 napi_create_string_utf8(env, "Hello from Node-API!", NAPI_AUTO_LENGTH, &value); 116 // Set the property on the object. 117 napi_set_property(env, object, name, value); 118 return object; 119} 120``` 121 122API declaration: 123 124```ts 125// index.d.ts 126export const createObject: () => { name: string }; 127``` 128 129ArkTS code: 130 131```ts 132import hilog from '@ohos.hilog' 133import testNapi from 'libentry.so' 134try { 135 const myObject = testNapi.createObject(); 136 hilog.info(0x0000, 'testTag', 'Test Node-API napi_create_object: %{public}s', myObject.name); 137} catch (error) { 138 hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_object errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message); 139} 140``` 141 142### napi_object_freeze 143 144Use **napi_object_freeze** to freeze an ArkTS object. After an object is frozen, new properties or methods cannot be added to the object, and the values of existing properties or methods cannot be modified. 145 146CPP code: 147 148```cpp 149#include "hilog/log.h" 150#include "napi/native_api.h" 151 152static napi_value ObjectFreeze(napi_env env, napi_callback_info info) 153{ 154 // Obtain the object passed from ArkTS. 155 size_t argc = 1; 156 napi_value argv[1] = {nullptr}; 157 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 158 159 // Call napi_object_freeze to freeze the object passed in. 160 napi_value objFreeze = argv[0]; 161 napi_status status = napi_object_freeze(env, objFreeze); 162 if (status == napi_ok) { 163 OH_LOG_INFO(LOG_APP, "Node-API napi_object_freeze success"); 164 } 165 // Return the frozen object to ArkTS. 166 return objFreeze; 167} 168``` 169 170API declaration: 171 172```ts 173// index.d.ts 174export interface Obj { 175 data: number 176 message: string 177} 178export const objectFreeze: (objFreeze: Object) => Obj; 179``` 180 181ArkTS code: 182 183```ts 184import hilog from '@ohos.hilog' 185import testNapi from 'libentry.so' 186try { 187 class Obj { 188 data: number = 0 189 message: string = "" 190 } 191 let obj: Obj = {data: 0, message: "hello world"}; 192 let objFreeze = testNapi.objectFreeze(obj); 193 hilog.info(0x0000, 'testTag', 'Test Node-API napi_object_freeze: %{public}s', (objFreeze.data = 1)); 194} catch (error) { 195 hilog.error(0x0000, 'testTag', 'Test Node-API napi_object_freeze error: %{public}s', error.message); 196} 197``` 198 199### napi_object_seal 200 201Use **napi_object_seal** to seal an ArkTS object. After an object is sealed, new properties cannot be added to the object, existing properties cannot be deleted, but the values of existing properties can be modified. 202 203CPP code: 204 205```cpp 206#include "hilog/log.h" 207#include "napi/native_api.h" 208 209static napi_value ObjectSeal(napi_env env, napi_callback_info info) 210{ 211 // Obtain the object passed from ArkTS. 212 size_t argc = 1; 213 napi_value argv[1] = {nullptr}; 214 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 215 // Call napi_object_seal to seal the object passed in. 216 napi_value objSeal = argv[0]; 217 napi_status status = napi_object_seal(env, objSeal); 218 if (status == napi_ok) { 219 OH_LOG_INFO(LOG_APP, "Node-API napi_object_seal success"); 220 } 221 // Return the sealed object to ArkTS. 222 return objSeal; 223} 224``` 225 226API declaration: 227 228```ts 229// index.d.ts 230export interface Obj { 231 data: number 232 message: string 233 id: number 234} 235export const objectSeal : (objSeal: Object) => Obj; 236``` 237 238ArkTS code: 239 240```ts 241import hilog from '@ohos.hilog' 242import testNapi from 'libentry.so' 243try { 244 class Obj { 245 data: number = 0 246 message: string = "" 247 // Optional property. 248 address?: number = 0 249 } 250 let obj: Obj = { data: 0, message: "hello world"}; 251 let objSeal = testNapi.objectSeal(obj); 252 hilog.info(0x0000, 'testTag', 'Test Node-API napi_object_seal: %{public}s', objSeal.message); 253 objSeal.data = 1; 254 hilog.info(0x0000, 'testTag', 'Test Node-API napi_object_seal: %{public}d', objSeal.data); 255 hilog.info(0x0000, 'testTag', 'Test Node-API napi_object_seal: %{public}d', (objSeal.id = 1)); 256} catch (error) { 257 hilog.error(0x0000, 'testTag', 'Test Node-API napi_object_seal error: %{public}s', error.message); 258} 259``` 260 261### napi_typeof 262 263Use **napi_typeof** to obtain the type of an ArkTS value. 264 265CPP code: 266 267```cpp 268#include "napi/native_api.h" 269 270static napi_value NapiTypeof(napi_env env, napi_callback_info info) 271{ 272 // Obtain the parameter. 273 size_t argc = 1; 274 napi_value args[1] = {nullptr}; 275 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 276 277 // Call napi_typeof to check the type of the ArkTS parameter passed in. 278 napi_valuetype valueType; 279 napi_status status = napi_typeof(env, args[0], &valueType); 280 if (status != napi_ok) { 281 napi_throw_error(env, nullptr, "Node-API napi_typeof fail"); 282 return nullptr; 283 } 284 // Convert the result to napi_value and return napi_value. 285 napi_value returnValue = nullptr; 286 switch(valueType) { 287 case napi_undefined: 288 napi_create_string_utf8(env, "Input type is napi_undefined", NAPI_AUTO_LENGTH, &returnValue); 289 break; 290 case napi_null: 291 napi_create_string_utf8(env, "Input type is napi_null", NAPI_AUTO_LENGTH, &returnValue); 292 break; 293 case napi_boolean: 294 napi_create_string_utf8(env, "Input type is napi_boolean", NAPI_AUTO_LENGTH, &returnValue); 295 break; 296 case napi_number: 297 napi_create_string_utf8(env, "Input type is napi_number", NAPI_AUTO_LENGTH, &returnValue); 298 break; 299 case napi_string: 300 napi_create_string_utf8(env, "Input type is napi_string", NAPI_AUTO_LENGTH, &returnValue); 301 break; 302 case napi_object: 303 napi_create_string_utf8(env, "Input type is napi_object", NAPI_AUTO_LENGTH, &returnValue); 304 break; 305 case napi_function: 306 napi_create_string_utf8(env, "Input type is napi_function", NAPI_AUTO_LENGTH, &returnValue); 307 break; 308 case napi_bigint: 309 napi_create_string_utf8(env, "Input type is napi_bigint", NAPI_AUTO_LENGTH, &returnValue); 310 break; 311 default: 312 napi_create_string_utf8(env, "unknown", NAPI_AUTO_LENGTH, &returnValue); 313 } 314 315 return returnValue; 316} 317``` 318 319API declaration: 320 321```ts 322// index.d.ts 323export const napiTypeof : <T>(value: T) => string | void; 324``` 325 326ArkTS code: 327 328```ts 329import hilog from '@ohos.hilog' 330import testNapi from 'libentry.so' 331try { 332 let varUndefined: undefined; 333 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(varUndefined)); 334 let varNull: null = null; 335 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(varNull)); 336 let varTrue= true; 337 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(varTrue)); 338 let varNum = 1; 339 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(varNum)); 340 let varString = "str"; 341 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(varString)); 342 class Obj { 343 id: number = 0 344 name: string = "" 345 } 346 let varObject: Obj = {id: 1, name: "LiLei"}; 347 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(varObject)); 348 const addNum = (a: number, b: number): number => a * b; 349 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(addNum)); 350 let varBigint = BigInt("1234567890123456789012345678901234567890"); 351 hilog.info(0x0000, 'testTag', 'Test Node-API napi_typeof: %{public}s', testNapi.napiTypeof(varBigint)); 352} catch (error) { 353 hilog.error(0x0000, 'testTag', 'Test Node-API napi_typeof error: %{public}s', error.message); 354} 355``` 356 357### napi_instanceof 358 359Use **napi_instanceof** to check whether an ArkTS object is an instance of the specified constructor. 360 361CPP code: 362 363```cpp 364#include "napi/native_api.h" 365 366static napi_value NapiInstanceof(napi_env env, napi_callback_info info) 367{ 368 // Obtain the two parameters passed from ArkTS. 369 size_t argc = 2; 370 napi_value args[2] = {nullptr}; 371 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 372 // Call napi_instanceof to check whether the given object is an instance of the given constructor. 373 bool result = true; 374 napi_status status = napi_instanceof(env, args[0], args[1], &result); 375 if (status != napi_ok) { 376 napi_throw_error(env, nullptr, "Node-API napi_instanceof fail"); 377 return nullptr; 378 } 379 // Convert the result to napi_value and return napi_value. 380 napi_value returnValue = nullptr; 381 napi_get_boolean(env, result, &returnValue); 382 383 return returnValue; 384} 385``` 386 387API declaration: 388 389```ts 390// index.d.ts 391export const napiInstanceof: (date: Object, construct: Object) => boolean | void; 392``` 393 394ArkTS code: 395 396```ts 397import hilog from '@ohos.hilog' 398import testNapi from 'libentry.so' 399try { 400 class Person { 401 name: string; 402 age: number; 403 404 constructor(name: string, age: number) { 405 this.name = name; 406 this.age = age; 407 } 408 } 409 const person = new Person("Alice", 30); 410 class Obj { 411 data: number = 0 412 message: string = "" 413 } 414 let obj: Obj = { data: 0, message: "hello world"}; 415 hilog.info(0x0000, 'testTag', 'Test Node-API napi_instanceof: %{public}s', testNapi.napiInstanceof(person, Person)); 416 hilog.info(0x0000, 'testTag', 'Test Node-API napi_instanceof: %{public}s', testNapi.napiInstanceof(obj, Person)); 417} catch (error) { 418 hilog.error(0x0000, 'testTag', 'Test Node-API napi_instanceof error: %{public}s', error.message); 419} 420``` 421 422### napi_type_tag_object 423 424Use **napi_type_tag_object** to associate the value of a **type_tag** pointer with an ArkTS object so that the object can be identified more accurately. 425 426### napi_check_object_type_tag 427 428Use **napi_check_object_type_tag** to check whether an ArkTS object is associated with a tag pointer. 429 430The type tags associate native types with ArkTS types, allowing ArkTS objects to be accurately identified and processed in C/C++. 431 432CPP code: 433 434```cpp 435#include "napi/native_api.h" 436 437#define NUMBERINT_FOUR 4 438// Define a static constant named napi_type_tag array to store type tags. 439static const napi_type_tag TagsData[NUMBERINT_FOUR] = { 440 {0x9e4b2449547061b3, 0x33999f8a6516c499}, 441 {0x1d55a794c53a726d, 0x43633f509f9c944e}, 442 // Default tag or no tag. 443 {0, 0}, 444 {0x6a971439f5b2e5d7, 0x531dc28a7e5317c0}, 445}; 446 447static napi_value SetTypeTagToObject(napi_env env, napi_callback_info info) 448{ 449 // Obtain the call information and parameters. 450 size_t argc = 2; 451 napi_value args[2] = {nullptr}; 452 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 453 // Obtain the index number and convert it to napi_value. 454 int32_t index = 0; 455 napi_get_value_int32(env, args[1], &index); 456 // Set the type tag for the parameter (object). 457 napi_status status = napi_type_tag_object(env, args[0], &TagsData[index]); 458 if (status != napi_ok) { 459 napi_throw_error(env, "Reconnect error", "napi_type_tag_object failed"); 460 return nullptr; 461 } 462 // Convert the bool value to napi_value and return it. 463 napi_value result = nullptr; 464 napi_get_boolean(env, true, &result); 465 return result; 466} 467 468static napi_value CheckObjectTypeTag(napi_env env, napi_callback_info info) 469{ 470 // Obtain the call information and parameters. 471 size_t argc = 2; 472 napi_value args[2] = {nullptr}; 473 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 474 // Obtain the index number and convert it to napi_value. 475 int32_t index = 0; 476 napi_get_value_int32(env, args[1], &index); 477 // Check the type tag of the object. 478 bool checkResult = true; 479 napi_check_object_type_tag(env, args[0], &TagsData[index], &checkResult); 480 // Convert the bool value to napi_value and return it. 481 napi_value checked = nullptr; 482 napi_get_boolean(env, checkResult, &checked); 483 484 return checked; 485} 486``` 487 488API declaration: 489 490```ts 491// index.d.ts 492export const setTypeTagToObject: (obj: Object, index: number) => boolean | void; 493export const checkObjectTypeTag: (obj: Object, index: number) => boolean; 494``` 495 496ArkTS code: 497 498```ts 499import hilog from '@ohos.hilog' 500import testNapi from 'libentry.so' 501class Obj { 502 data: number = 0 503 message: string = "" 504} 505let objA: Obj = { data: 0, message: "hello world"}; 506let objB: Obj = { data: 10, message: "typetag"}; 507hilog.info(0x0000, 'testTag', 'Test Node-API napi_type_tag_object objA -> 0: %{public}s', testNapi.setTypeTagToObject(objA, 0)); 508hilog.info(0x0000, 'testTag', 'Test Node-API napi_type_tag_object objB -> 0: %{public}s', testNapi.setTypeTagToObject(objB, 0)); 509hilog.info(0x0000, 'testTag', 'Test Node-API napi_check_object_type_tag objA -> 0: %{public}s', testNapi.checkObjectTypeTag(objA, 0)); 510hilog.info(0x0000, 'testTag', 'Test Node-API napi_check_object_type_tag objB -> 1: %{public}s', testNapi.checkObjectTypeTag(objB, 1)); 511``` 512 513### napi_create_external 514 515Use **napi_create_external** to create an ArkTS external object wrapping a custom C/C++ object and expose it to ArkTS. With this API, you can create a Node-API value that contains a pointer to a custom C/C++ object so that the object can be accessed and managed by ArkTS. 516 517CPP code: 518 519```cpp 520#include <cstdlib> 521#include <string> 522#include "napi/native_api.h" 523 524// Callback used to release the external data. 525void finalizeCallback(napi_env env, void *data, void *hint) { 526 // Release external data. 527 free(data); 528} 529 530static napi_value GetExternalType(napi_env env, napi_callback_info info) 531{ 532 size_t argc = 1; 533 napi_value args[1] = {nullptr}; 534 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 535 // Obtain the data type of the parameter. 536 napi_valuetype valueType; 537 napi_typeof(env, args[0], &valueType); 538 napi_value returnValue = nullptr; 539 if (valueType == napi_external) { 540 // If the data type is napi_external, return true. 541 napi_get_boolean(env, true, &returnValue); 542 } else { 543 napi_get_boolean(env, false, &returnValue); 544 } 545 return returnValue; 546} 547 548static napi_value CreateExternal(napi_env env, napi_callback_info info) 549{ 550 // Set the external data size to 10. 551 const size_t dataSize = 10; 552 // Allocate memory to the external data. 553 void *data = malloc(dataSize); 554 // Initialize the external data. 555 memset(data, 0, dataSize); 556 napi_value result = nullptr; 557 // Return an object with external data. 558 napi_status status = napi_create_external(env, data, finalizeCallback, nullptr, &result); 559 if (status != napi_ok) { 560 napi_throw_error(env, nullptr, " Node-API Failed to create external data"); 561 return nullptr; 562 } 563 return result; 564} 565``` 566 567API declaration: 568 569```ts 570// index.d.ts 571export const createExternal: () => Object; 572export const getExternalType: (externalData: Object) => boolean; 573``` 574 575ArkTS code: 576 577```ts 578import hilog from '@ohos.hilog' 579import testNapi from 'libentry.so' 580const externalData = testNapi.createExternal(); 581hilog.info(0x0000, 'testTag', 'Test Node-API napi_create_external:%{public}s', testNapi.getExternalType(externalData)); 582``` 583 584### napi_get_value_external 585 586Use **napi_get_value_external** to obtain the ArkTS data from the external object created by **napi_create_external**. 587 588CPP code: 589 590```cpp 591#include "napi/native_api.h" 592 593static int external = 5; 594static napi_value GetValueExternal(napi_env env, napi_callback_info info) 595{ 596 // Create external data. 597 int* data = &external; 598 napi_value setExternal = nullptr; 599 napi_create_external(env, data, nullptr, nullptr, &setExternal); 600 // Obtain the value of the external data. 601 void *getExternal; 602 napi_get_value_external(env, setExternal, &getExternal); 603 // Return the obtained external data. 604 napi_value result = nullptr; 605 napi_create_int32(env, *(int *)getExternal, &result); 606 return result; 607} 608``` 609 610API declaration: 611 612```ts 613// index.d.ts 614export const getValueExternal: () => number; 615``` 616 617ArkTS code: 618 619```ts 620import hilog from '@ohos.hilog' 621import testNapi from 'libentry.so' 622hilog.info(0x0000, 'Node-API', 'get_value_external:%{public}d', testNapi.getValueExternal()); 623``` 624 625### napi_create_symbol 626 627Use **napi_create_symbol** to create a symbol. Symbol is a special data type used to indicate a unique identifier. Unlike strings or numbers, the value of a symbol is unique. Even if two symbols have the same description, they are not equal. Symbols are often used as keys for object properties to ensure property uniqueness. 628 629CPP code: 630 631```cpp 632#include "napi/native_api.h" 633 634static napi_value CreateSymbol(napi_env env, napi_callback_info info) 635{ 636 napi_value result = nullptr; 637 const char *des = "only"; 638 // Use napi_create_string_utf8 to create a description string. 639 napi_create_string_utf8(env, des, NAPI_AUTO_LENGTH, &result); 640 napi_value returnSymbol = nullptr; 641 // Create a symbol and return it. 642 napi_create_symbol(env, result, &returnSymbol); 643 return returnSymbol; 644} 645``` 646 647API declaration: 648 649```ts 650// index.d.ts 651export const createSymbol : () => symbol; 652``` 653 654ArkTS code: 655 656```ts 657import hilog from '@ohos.hilog' 658import testNapi from 'libentry.so' 659let varSymbol = testNapi.createSymbol(); 660hilog.info(0x0000, 'Node-API', 'createSymbol:%{public}s', typeof varSymbol); 661``` 662 663To print logs in the native CPP, add the following information to the **CMakeLists.txt** file and add the header file by using **#include "hilog/log.h"**. 664 665```text 666// CMakeLists.txt 667add_definitions( "-DLOG_DOMAIN=0xd0d0" ) 668add_definitions( "-DLOG_TAG=\"testTag\"" ) 669target_link_libraries(entry PUBLIC libhilog_ndk.z.so) 670``` 671