1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width"> 6 <meta name="nodejs.org:node-version" content="v14.21.2"> 7 <title>C++ addons | Node.js v14.21.2 Documentation</title> 8 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic&display=fallback"> 9 <link rel="stylesheet" href="assets/style.css"> 10 <link rel="stylesheet" href="assets/hljs.css"> 11 <link rel="canonical" href="https://nodejs.org/api/addons.html"> 12</head> 13<body class="alt apidoc" id="api-section-addons"> 14 <div id="content" class="clearfix"> 15 <div id="column2" class="interior"> 16 <div id="intro" class="interior"> 17 <a href="/" title="Go back to the home page"> 18 Node.js 19 </a> 20 </div> 21 <ul> 22<li><a href="documentation.html" class="nav-documentation">About this documentation</a></li> 23<li><a href="synopsis.html" class="nav-synopsis">Usage and example</a></li> 24</ul> 25<hr class="line"> 26<ul> 27<li><a href="assert.html" class="nav-assert">Assertion testing</a></li> 28<li><a href="async_hooks.html" class="nav-async_hooks">Async hooks</a></li> 29<li><a href="buffer.html" class="nav-buffer">Buffer</a></li> 30<li><a href="addons.html" class="nav-addons active">C++ addons</a></li> 31<li><a href="n-api.html" class="nav-n-api">C/C++ addons with Node-API</a></li> 32<li><a href="embedding.html" class="nav-embedding">C++ embedder API</a></li> 33<li><a href="child_process.html" class="nav-child_process">Child processes</a></li> 34<li><a href="cluster.html" class="nav-cluster">Cluster</a></li> 35<li><a href="cli.html" class="nav-cli">Command-line options</a></li> 36<li><a href="console.html" class="nav-console">Console</a></li> 37<li><a href="corepack.html" class="nav-corepack">Corepack</a></li> 38<li><a href="crypto.html" class="nav-crypto">Crypto</a></li> 39<li><a href="debugger.html" class="nav-debugger">Debugger</a></li> 40<li><a href="deprecations.html" class="nav-deprecations">Deprecated APIs</a></li> 41<li><a href="diagnostics_channel.html" class="nav-diagnostics_channel">Diagnostics Channel</a></li> 42<li><a href="dns.html" class="nav-dns">DNS</a></li> 43<li><a href="domain.html" class="nav-domain">Domain</a></li> 44<li><a href="errors.html" class="nav-errors">Errors</a></li> 45<li><a href="events.html" class="nav-events">Events</a></li> 46<li><a href="fs.html" class="nav-fs">File system</a></li> 47<li><a href="globals.html" class="nav-globals">Globals</a></li> 48<li><a href="http.html" class="nav-http">HTTP</a></li> 49<li><a href="http2.html" class="nav-http2">HTTP/2</a></li> 50<li><a href="https.html" class="nav-https">HTTPS</a></li> 51<li><a href="inspector.html" class="nav-inspector">Inspector</a></li> 52<li><a href="intl.html" class="nav-intl">Internationalization</a></li> 53<li><a href="modules.html" class="nav-modules">Modules: CommonJS modules</a></li> 54<li><a href="esm.html" class="nav-esm">Modules: ECMAScript modules</a></li> 55<li><a href="module.html" class="nav-module">Modules: <code>module</code> API</a></li> 56<li><a href="packages.html" class="nav-packages">Modules: Packages</a></li> 57<li><a href="net.html" class="nav-net">Net</a></li> 58<li><a href="os.html" class="nav-os">OS</a></li> 59<li><a href="path.html" class="nav-path">Path</a></li> 60<li><a href="perf_hooks.html" class="nav-perf_hooks">Performance hooks</a></li> 61<li><a href="policy.html" class="nav-policy">Policies</a></li> 62<li><a href="process.html" class="nav-process">Process</a></li> 63<li><a href="punycode.html" class="nav-punycode">Punycode</a></li> 64<li><a href="querystring.html" class="nav-querystring">Query strings</a></li> 65<li><a href="readline.html" class="nav-readline">Readline</a></li> 66<li><a href="repl.html" class="nav-repl">REPL</a></li> 67<li><a href="report.html" class="nav-report">Report</a></li> 68<li><a href="stream.html" class="nav-stream">Stream</a></li> 69<li><a href="string_decoder.html" class="nav-string_decoder">String decoder</a></li> 70<li><a href="timers.html" class="nav-timers">Timers</a></li> 71<li><a href="tls.html" class="nav-tls">TLS/SSL</a></li> 72<li><a href="tracing.html" class="nav-tracing">Trace events</a></li> 73<li><a href="tty.html" class="nav-tty">TTY</a></li> 74<li><a href="dgram.html" class="nav-dgram">UDP/datagram</a></li> 75<li><a href="url.html" class="nav-url">URL</a></li> 76<li><a href="util.html" class="nav-util">Utilities</a></li> 77<li><a href="v8.html" class="nav-v8">V8</a></li> 78<li><a href="vm.html" class="nav-vm">VM</a></li> 79<li><a href="wasi.html" class="nav-wasi">WASI</a></li> 80<li><a href="worker_threads.html" class="nav-worker_threads">Worker threads</a></li> 81<li><a href="zlib.html" class="nav-zlib">Zlib</a></li> 82</ul> 83<hr class="line"> 84<ul> 85<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">Code repository and issue tracker</a></li> 86</ul> 87 </div> 88 89 <div id="column1" data-id="addons" class="interior"> 90 <header> 91 <div class="header-container"> 92 <h1>Node.js v14.21.2 documentation</h1> 93 <button class="theme-toggle-btn" id="theme-toggle-btn" title="Toggle dark mode/light mode" aria-label="Toggle dark mode/light mode" hidden> 94 <svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" height="24" width="24"> 95 <path fill="none" d="M0 0h24v24H0z" /> 96 <path d="M11.1 12.08c-2.33-4.51-.5-8.48.53-10.07C6.27 2.2 1.98 6.59 1.98 12c0 .14.02.28.02.42.62-.27 1.29-.42 2-.42 1.66 0 3.18.83 4.1 2.15A4.01 4.01 0 0111 18c0 1.52-.87 2.83-2.12 3.51.98.32 2.03.5 3.11.5 3.5 0 6.58-1.8 8.37-4.52-2.36.23-6.98-.97-9.26-5.41z"/> 97 <path d="M7 16h-.18C6.4 14.84 5.3 14 4 14c-1.66 0-3 1.34-3 3s1.34 3 3 3h3c1.1 0 2-.9 2-2s-.9-2-2-2z"/> 98 </svg> 99 <svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" height="24" width="24"> 100 <path d="M0 0h24v24H0z" fill="none" /> 101 <path d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"/> 102 </svg> 103 </button> 104 </div> 105 <div id="gtoc"> 106 <ul> 107 <li> 108 <a href="index.html">Index</a> 109 </li> 110 <li> 111 <a href="all.html">View on single page</a> 112 </li> 113 <li> 114 <a href="addons.json">View as JSON</a> 115 </li> 116 117 <li class="version-picker"> 118 <a href="#">View another version <span>▼</span></a> 119 <ol class="version-picker"><li><a href="https://nodejs.org/docs/latest-v19.x/api/addons.html">19.x</a></li> 120<li><a href="https://nodejs.org/docs/latest-v18.x/api/addons.html">18.x <b>LTS</b></a></li> 121<li><a href="https://nodejs.org/docs/latest-v17.x/api/addons.html">17.x</a></li> 122<li><a href="https://nodejs.org/docs/latest-v16.x/api/addons.html">16.x <b>LTS</b></a></li> 123<li><a href="https://nodejs.org/docs/latest-v15.x/api/addons.html">15.x</a></li> 124<li><a href="https://nodejs.org/docs/latest-v14.x/api/addons.html">14.x <b>LTS</b></a></li> 125<li><a href="https://nodejs.org/docs/latest-v13.x/api/addons.html">13.x</a></li> 126<li><a href="https://nodejs.org/docs/latest-v12.x/api/addons.html">12.x</a></li> 127<li><a href="https://nodejs.org/docs/latest-v11.x/api/addons.html">11.x</a></li> 128<li><a href="https://nodejs.org/docs/latest-v10.x/api/addons.html">10.x</a></li> 129<li><a href="https://nodejs.org/docs/latest-v9.x/api/addons.html">9.x</a></li> 130<li><a href="https://nodejs.org/docs/latest-v8.x/api/addons.html">8.x</a></li> 131<li><a href="https://nodejs.org/docs/latest-v7.x/api/addons.html">7.x</a></li> 132<li><a href="https://nodejs.org/docs/latest-v6.x/api/addons.html">6.x</a></li> 133<li><a href="https://nodejs.org/docs/latest-v5.x/api/addons.html">5.x</a></li> 134<li><a href="https://nodejs.org/docs/latest-v4.x/api/addons.html">4.x</a></li> 135<li><a href="https://nodejs.org/docs/latest-v0.12.x/api/addons.html">0.12.x</a></li> 136<li><a href="https://nodejs.org/docs/latest-v0.10.x/api/addons.html">0.10.x</a></li></ol> 137 </li> 138 139 <li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/master/doc/api/addons.md">Edit on GitHub</a></li> 140 </ul> 141 </div> 142 <hr> 143 </header> 144 145 <details id="toc" open><summary>Table of contents</summary><ul> 146<li><a href="#addons_c_addons">C++ addons</a> 147<ul> 148<li><a href="#addons_hello_world">Hello world</a> 149<ul> 150<li><a href="#addons_context_aware_addons">Context-aware addons</a> 151<ul> 152<li><a href="#addons_worker_support">Worker support</a></li> 153</ul> 154</li> 155<li><a href="#addons_building">Building</a></li> 156<li><a href="#addons_linking_to_libraries_included_with_node_js">Linking to libraries included with Node.js</a></li> 157<li><a href="#addons_loading_addons_using_require">Loading addons using <code>require()</code></a></li> 158</ul> 159</li> 160<li><a href="#addons_native_abstractions_for_node_js">Native abstractions for Node.js</a></li> 161<li><span class="stability_2"><a href="#addons_node_api">Node-API</a></span></li> 162<li><a href="#addons_addon_examples">Addon examples</a> 163<ul> 164<li><a href="#addons_function_arguments">Function arguments</a></li> 165<li><a href="#addons_callbacks">Callbacks</a></li> 166<li><a href="#addons_object_factory">Object factory</a></li> 167<li><a href="#addons_function_factory">Function factory</a></li> 168<li><a href="#addons_wrapping_c_objects">Wrapping C++ objects</a></li> 169<li><a href="#addons_factory_of_wrapped_objects">Factory of wrapped objects</a></li> 170<li><a href="#addons_passing_wrapped_objects_around">Passing wrapped objects around</a></li> 171</ul> 172</li> 173</ul> 174</li> 175</ul></details> 176 177 <div id="apicontent"> 178 <h2>C++ addons<span><a class="mark" href="#addons_c_addons" id="addons_c_addons">#</a></span></h2> 179 180 181<p><em>Addons</em> are dynamically-linked shared objects written in C++. The 182<a href="modules.html#modules_require_id"><code>require()</code></a> function can load addons as ordinary Node.js modules. 183Addons provide an interface between JavaScript and C/C++ libraries.</p> 184<p>There are three options for implementing addons: Node-API, nan, or direct 185use of internal V8, libuv and Node.js libraries. Unless there is a need for 186direct access to functionality which is not exposed by Node-API, use Node-API. 187Refer to <a href="n-api.html">C/C++ addons with Node-API</a> for more information on 188Node-API.</p> 189<p>When not using Node-API, implementing addons is complicated, 190involving knowledge of several components and APIs:</p> 191<ul> 192<li> 193<p><a href="https://v8.dev/">V8</a>: the C++ library Node.js uses to provide the 194JavaScript implementation. V8 provides the mechanisms for creating objects, 195calling functions, etc. V8's API is documented mostly in the 196<code>v8.h</code> header file (<code>deps/v8/include/v8.h</code> in the Node.js source 197tree), which is also available <a href="https://v8docs.nodesource.com/">online</a>.</p> 198</li> 199<li> 200<p><a href="https://github.com/libuv/libuv">libuv</a>: The C library that implements the Node.js event loop, its worker 201threads and all of the asynchronous behaviors of the platform. It also 202serves as a cross-platform abstraction library, giving easy, POSIX-like 203access across all major operating systems to many common system tasks, such 204as interacting with the filesystem, sockets, timers, and system events. libuv 205also provides a threading abstraction similar to POSIX threads for 206more sophisticated asynchronous addons that need to move beyond the 207standard event loop. Addon authors should 208avoid blocking the event loop with I/O or other time-intensive tasks by 209offloading work via libuv to non-blocking system operations, worker threads, 210or a custom use of libuv threads.</p> 211</li> 212<li> 213<p>Internal Node.js libraries. Node.js itself exports C++ APIs that addons can 214use, the most important of which is the <code>node::ObjectWrap</code> class.</p> 215</li> 216<li> 217<p>Node.js includes other statically linked libraries including OpenSSL. These 218other libraries are located in the <code>deps/</code> directory in the Node.js source 219tree. Only the libuv, OpenSSL, V8 and zlib symbols are purposefully 220re-exported by Node.js and may be used to various extents by addons. See 221<a href="#addons_linking_to_libraries_included_with_node_js">Linking to libraries included with Node.js</a> for additional information.</p> 222</li> 223</ul> 224<p>All of the following examples are available for <a href="https://github.com/nodejs/node-addon-examples">download</a> and may 225be used as the starting-point for an addon.</p> 226<section><h3>Hello world<span><a class="mark" href="#addons_hello_world" id="addons_hello_world">#</a></span></h3> 227<p>This "Hello world" example is a simple addon, written in C++, that is the 228equivalent of the following JavaScript code:</p> 229<pre><code class="language-js"><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">hello</span> = <span class="hljs-function">() =></span> <span class="hljs-string">'world'</span>;</code></pre> 230<p>First, create the file <code>hello.cc</code>:</p> 231<pre><code class="language-cpp"><span class="hljs-comment">// hello.cc</span> 232<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 233 234<span class="hljs-keyword">namespace</span> demo { 235 236<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 237<span class="hljs-keyword">using</span> v8::Isolate; 238<span class="hljs-keyword">using</span> v8::Local; 239<span class="hljs-keyword">using</span> v8::Object; 240<span class="hljs-keyword">using</span> v8::String; 241<span class="hljs-keyword">using</span> v8::Value; 242 243<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Method</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 244 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 245 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(String::<span class="hljs-built_in">NewFromUtf8</span>( 246 isolate, <span class="hljs-string">"world"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 247} 248 249<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Initialize</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 250 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"hello"</span>, Method); 251} 252 253<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Initialize) 254 255} <span class="hljs-comment">// namespace demo</span></code></pre> 256<p>All Node.js addons must export an initialization function following 257the pattern:</p> 258<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Initialize</span><span class="hljs-params">(Local<Object> exports)</span></span>; 259<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Initialize)</code></pre> 260<p>There is no semi-colon after <code>NODE_MODULE</code> as it's not a function (see 261<code>node.h</code>).</p> 262<p>The <code>module_name</code> must match the filename of the final binary (excluding 263the <code>.node</code> suffix).</p> 264<p>In the <code>hello.cc</code> example, then, the initialization function is <code>Initialize</code> 265and the addon module name is <code>addon</code>.</p> 266<p>When building addons with <code>node-gyp</code>, using the macro <code>NODE_GYP_MODULE_NAME</code> as 267the first parameter of <code>NODE_MODULE()</code> will ensure that the name of the final 268binary will be passed to <code>NODE_MODULE()</code>.</p> 269<h4>Context-aware addons<span><a class="mark" href="#addons_context_aware_addons" id="addons_context_aware_addons">#</a></span></h4> 270<p>There are environments in which Node.js addons may need to be loaded multiple 271times in multiple contexts. For example, the <a href="https://electronjs.org/">Electron</a> runtime runs multiple 272instances of Node.js in a single process. Each instance will have its own 273<code>require()</code> cache, and thus each instance will need a native addon to behave 274correctly when loaded via <code>require()</code>. This means that the addon 275must support multiple initializations.</p> 276<p>A context-aware addon can be constructed by using the macro 277<code>NODE_MODULE_INITIALIZER</code>, which expands to the name of a function which Node.js 278will expect to find when it loads an addon. An addon can thus be initialized as 279in the following example:</p> 280<pre><code class="language-cpp"><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> v8; 281 282<span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-function">NODE_MODULE_EXPORT <span class="hljs-type">void</span> 283<span class="hljs-title">NODE_MODULE_INITIALIZER</span><span class="hljs-params">(Local<Object> exports, 284 Local<Value> <span class="hljs-keyword">module</span>, 285 Local<Context> context)</span> </span>{ 286 <span class="hljs-comment">/* Perform addon initialization steps here. */</span> 287}</code></pre> 288<p>Another option is to use the macro <code>NODE_MODULE_INIT()</code>, which will also 289construct a context-aware addon. Unlike <code>NODE_MODULE()</code>, which is used to 290construct an addon around a given addon initializer function, 291<code>NODE_MODULE_INIT()</code> serves as the declaration of such an initializer to be 292followed by a function body.</p> 293<p>The following three variables may be used inside the function body following an 294invocation of <code>NODE_MODULE_INIT()</code>:</p> 295<ul> 296<li><code>Local<Object> exports</code>,</li> 297<li><code>Local<Value> module</code>, and</li> 298<li><code>Local<Context> context</code></li> 299</ul> 300<p>The choice to build a context-aware addon carries with it the responsibility of 301carefully managing global static data. Since the addon may be loaded multiple 302times, potentially even from different threads, any global static data stored 303in the addon must be properly protected, and must not contain any persistent 304references to JavaScript objects. The reason for this is that JavaScript 305objects are only valid in one context, and will likely cause a crash when 306accessed from the wrong context or from a different thread than the one on which 307they were created.</p> 308<p>The context-aware addon can be structured to avoid global static data by 309performing the following steps:</p> 310<ul> 311<li>Define a class which will hold per-addon-instance data and which has a static 312member of the form 313<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">DeleteInstance</span><span class="hljs-params">(<span class="hljs-type">void</span>* data)</span> </span>{ 314 <span class="hljs-comment">// Cast `data` to an instance of the class and delete it.</span> 315}</code></pre> 316</li> 317<li>Heap-allocate an instance of this class in the addon initializer. This can be 318accomplished using the <code>new</code> keyword.</li> 319<li>Call <code>node::AddEnvironmentCleanupHook()</code>, passing it the above-created 320instance and a pointer to <code>DeleteInstance()</code>. This will ensure the instance is 321deleted when the environment is torn down.</li> 322<li>Store the instance of the class in a <code>v8::External</code>, and</li> 323<li>Pass the <code>v8::External</code> to all methods exposed to JavaScript by passing it 324to <code>v8::FunctionTemplate::New()</code> or <code>v8::Function::New()</code> which creates the 325native-backed JavaScript functions. The third parameter of 326<code>v8::FunctionTemplate::New()</code> or <code>v8::Function::New()</code> accepts the 327<code>v8::External</code> and makes it available in the native callback using the 328<code>v8::FunctionCallbackInfo::Data()</code> method.</li> 329</ul> 330<p>This will ensure that the per-addon-instance data reaches each binding that can 331be called from JavaScript. The per-addon-instance data must also be passed into 332any asynchronous callbacks the addon may create.</p> 333<p>The following example illustrates the implementation of a context-aware addon:</p> 334<pre><code class="language-cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 335 336<span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> v8; 337 338<span class="hljs-keyword">class</span> <span class="hljs-title class_">AddonData</span> { 339 <span class="hljs-keyword">public</span>: 340 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">AddonData</span><span class="hljs-params">(Isolate* isolate)</span>: 341 call_count(<span class="hljs-number">0</span>) {</span> 342 <span class="hljs-comment">// Ensure this per-addon-instance data is deleted at environment cleanup.</span> 343 node::<span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, DeleteInstance, <span class="hljs-keyword">this</span>); 344 } 345 346 <span class="hljs-comment">// Per-addon data.</span> 347 <span class="hljs-type">int</span> call_count; 348 349 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">DeleteInstance</span><span class="hljs-params">(<span class="hljs-type">void</span>* data)</span> </span>{ 350 <span class="hljs-keyword">delete</span> <span class="hljs-built_in">static_cast</span><AddonData*>(data); 351 } 352}; 353 354<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Method</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& info)</span> </span>{ 355 <span class="hljs-comment">// Retrieve the per-addon-instance data.</span> 356 AddonData* data = 357 <span class="hljs-built_in">reinterpret_cast</span><AddonData*>(info.<span class="hljs-built_in">Data</span>().<span class="hljs-built_in">As</span><External>()-><span class="hljs-built_in">Value</span>()); 358 data->call_count++; 359 info.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>((<span class="hljs-type">double</span>)data->call_count); 360} 361 362<span class="hljs-comment">// Initialize this addon to be context-aware.</span> 363<span class="hljs-built_in">NODE_MODULE_INIT</span>(<span class="hljs-comment">/* exports, module, context */</span>) { 364 Isolate* isolate = context-><span class="hljs-built_in">GetIsolate</span>(); 365 366 <span class="hljs-comment">// Create a new instance of `AddonData` for this instance of the addon and</span> 367 <span class="hljs-comment">// tie its life cycle to that of the Node.js environment.</span> 368 AddonData* data = <span class="hljs-keyword">new</span> <span class="hljs-built_in">AddonData</span>(isolate); 369 370 <span class="hljs-comment">// Wrap the data in a `v8::External` so we can pass it to the method we</span> 371 <span class="hljs-comment">// expose.</span> 372 Local<External> external = External::<span class="hljs-built_in">New</span>(isolate, data); 373 374 <span class="hljs-comment">// Expose the method `Method` to JavaScript, and make sure it receives the</span> 375 <span class="hljs-comment">// per-addon-instance data we created above by passing `external` as the</span> 376 <span class="hljs-comment">// third parameter to the `FunctionTemplate` constructor.</span> 377 exports-><span class="hljs-built_in">Set</span>(context, 378 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"method"</span>).<span class="hljs-built_in">ToLocalChecked</span>(), 379 FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, Method, external) 380 -><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()).<span class="hljs-built_in">FromJust</span>(); 381}</code></pre> 382<h5>Worker support<span><a class="mark" href="#addons_worker_support" id="addons_worker_support">#</a></span></h5> 383<div class="api_metadata"> 384<details class="changelog"><summary>History</summary> 385<table> 386<tbody><tr><th>Version</th><th>Changes</th></tr> 387<tr><td>v14.8.0</td> 388<td><p>Cleanup hooks may now be asynchronous.</p></td></tr> 389</tbody></table> 390</details> 391</div> 392<p>In order to be loaded from multiple Node.js environments, 393such as a main thread and a Worker thread, an add-on needs to either:</p> 394<ul> 395<li>Be an Node-API addon, or</li> 396<li>Be declared as context-aware using <code>NODE_MODULE_INIT()</code> as described above</li> 397</ul> 398<p>In order to support <a href="worker_threads.html#worker_threads_class_worker"><code>Worker</code></a> threads, addons need to clean up any resources 399they may have allocated when such a thread exists. This can be achieved through 400the usage of the <code>AddEnvironmentCleanupHook()</code> function:</p> 401<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">AddEnvironmentCleanupHook</span><span class="hljs-params">(v8::Isolate* isolate, 402 <span class="hljs-type">void</span> (*fun)(<span class="hljs-type">void</span>* arg), 403 <span class="hljs-type">void</span>* arg)</span></span>;</code></pre> 404<p>This function adds a hook that will run before a given Node.js instance shuts 405down. If necessary, such hooks can be removed before they are run using 406<code>RemoveEnvironmentCleanupHook()</code>, which has the same signature. Callbacks are 407run in last-in first-out order.</p> 408<p>If necessary, there is an additional pair of <code>AddEnvironmentCleanupHook()</code> 409and <code>RemoveEnvironmentCleanupHook()</code> overloads, where the cleanup hook takes a 410callback function. This can be used for shutting down asynchronous resources, 411such as any libuv handles registered by the addon.</p> 412<p>The following <code>addon.cc</code> uses <code>AddEnvironmentCleanupHook</code>:</p> 413<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 414<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 415<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><assert.h></span></span> 416<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span> 417 418<span class="hljs-keyword">using</span> node::AddEnvironmentCleanupHook; 419<span class="hljs-keyword">using</span> v8::HandleScope; 420<span class="hljs-keyword">using</span> v8::Isolate; 421<span class="hljs-keyword">using</span> v8::Local; 422<span class="hljs-keyword">using</span> v8::Object; 423 424<span class="hljs-comment">// Note: In a real-world application, do not rely on static/global data.</span> 425<span class="hljs-keyword">static</span> <span class="hljs-type">char</span> cookie[] = <span class="hljs-string">"yum yum"</span>; 426<span class="hljs-keyword">static</span> <span class="hljs-type">int</span> cleanup_cb1_called = <span class="hljs-number">0</span>; 427<span class="hljs-keyword">static</span> <span class="hljs-type">int</span> cleanup_cb2_called = <span class="hljs-number">0</span>; 428 429<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">cleanup_cb1</span><span class="hljs-params">(<span class="hljs-type">void</span>* arg)</span> </span>{ 430 Isolate* isolate = <span class="hljs-built_in">static_cast</span><Isolate*>(arg); 431 <span class="hljs-function">HandleScope <span class="hljs-title">scope</span><span class="hljs-params">(isolate)</span></span>; 432 Local<Object> obj = Object::<span class="hljs-built_in">New</span>(isolate); 433 <span class="hljs-built_in">assert</span>(!obj.<span class="hljs-built_in">IsEmpty</span>()); <span class="hljs-comment">// assert VM is still alive</span> 434 <span class="hljs-built_in">assert</span>(obj-><span class="hljs-built_in">IsObject</span>()); 435 cleanup_cb1_called++; 436} 437 438<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">cleanup_cb2</span><span class="hljs-params">(<span class="hljs-type">void</span>* arg)</span> </span>{ 439 <span class="hljs-built_in">assert</span>(arg == <span class="hljs-built_in">static_cast</span><<span class="hljs-type">void</span>*>(cookie)); 440 cleanup_cb2_called++; 441} 442 443<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">sanity_check</span><span class="hljs-params">(<span class="hljs-type">void</span>*)</span> </span>{ 444 <span class="hljs-built_in">assert</span>(cleanup_cb1_called == <span class="hljs-number">1</span>); 445 <span class="hljs-built_in">assert</span>(cleanup_cb2_called == <span class="hljs-number">1</span>); 446} 447 448<span class="hljs-comment">// Initialize this addon to be context-aware.</span> 449<span class="hljs-built_in">NODE_MODULE_INIT</span>(<span class="hljs-comment">/* exports, module, context */</span>) { 450 Isolate* isolate = context-><span class="hljs-built_in">GetIsolate</span>(); 451 452 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, sanity_check, <span class="hljs-literal">nullptr</span>); 453 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, cleanup_cb2, cookie); 454 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, cleanup_cb1, isolate); 455}</code></pre> 456<p>Test in JavaScript by running:</p> 457<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 458<span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>);</code></pre> 459<h4>Building<span><a class="mark" href="#addons_building" id="addons_building">#</a></span></h4> 460<p>Once the source code has been written, it must be compiled into the binary 461<code>addon.node</code> file. To do so, create a file called <code>binding.gyp</code> in the 462top-level of the project describing the build configuration of the module 463using a JSON-like format. This file is used by <a href="https://github.com/nodejs/node-gyp">node-gyp</a>, a tool written 464specifically to compile Node.js addons.</p> 465<pre><code class="language-json"><span class="hljs-punctuation">{</span> 466 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 467 <span class="hljs-punctuation">{</span> 468 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 469 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"hello.cc"</span> <span class="hljs-punctuation">]</span> 470 <span class="hljs-punctuation">}</span> 471 <span class="hljs-punctuation">]</span> 472<span class="hljs-punctuation">}</span></code></pre> 473<p>A version of the <code>node-gyp</code> utility is bundled and distributed with 474Node.js as part of <code>npm</code>. This version is not made directly available for 475developers to use and is intended only to support the ability to use the 476<code>npm install</code> command to compile and install addons. Developers who wish to 477use <code>node-gyp</code> directly can install it using the command 478<code>npm install -g node-gyp</code>. See the <code>node-gyp</code> <a href="https://github.com/nodejs/node-gyp#installation">installation instructions</a> for 479more information, including platform-specific requirements.</p> 480<p>Once the <code>binding.gyp</code> file has been created, use <code>node-gyp configure</code> to 481generate the appropriate project build files for the current platform. This 482will generate either a <code>Makefile</code> (on Unix platforms) or a <code>vcxproj</code> file 483(on Windows) in the <code>build/</code> directory.</p> 484<p>Next, invoke the <code>node-gyp build</code> command to generate the compiled <code>addon.node</code> 485file. This will be put into the <code>build/Release/</code> directory.</p> 486<p>When using <code>npm install</code> to install a Node.js addon, npm uses its own bundled 487version of <code>node-gyp</code> to perform this same set of actions, generating a 488compiled version of the addon for the user's platform on demand.</p> 489<p>Once built, the binary addon can be used from within Node.js by pointing 490<a href="modules.html#modules_require_id"><code>require()</code></a> to the built <code>addon.node</code> module:</p> 491<pre><code class="language-js"><span class="hljs-comment">// hello.js</span> 492<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 493 494<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(addon.<span class="hljs-title function_">hello</span>()); 495<span class="hljs-comment">// Prints: 'world'</span></code></pre> 496<p>Because the exact path to the compiled addon binary can vary depending on how 497it is compiled (i.e. sometimes it may be in <code>./build/Debug/</code>), addons can use 498the <a href="https://github.com/TooTallNate/node-bindings">bindings</a> package to load the compiled module.</p> 499<p>While the <code>bindings</code> package implementation is more sophisticated in how it 500locates addon modules, it is essentially using a <code>try…catch</code> pattern similar to:</p> 501<pre><code class="language-js"><span class="hljs-keyword">try</span> { 502 <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon.node'</span>); 503} <span class="hljs-keyword">catch</span> (err) { 504 <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Debug/addon.node'</span>); 505}</code></pre> 506<h4>Linking to libraries included with Node.js<span><a class="mark" href="#addons_linking_to_libraries_included_with_node_js" id="addons_linking_to_libraries_included_with_node_js">#</a></span></h4> 507<p>Node.js uses statically linked libraries such as V8, libuv and OpenSSL. All 508addons are required to link to V8 and may link to any of the other dependencies 509as well. Typically, this is as simple as including the appropriate 510<code>#include <...></code> statements (e.g. <code>#include <v8.h></code>) and <code>node-gyp</code> will locate 511the appropriate headers automatically. However, there are a few caveats to be 512aware of:</p> 513<ul> 514<li> 515<p>When <code>node-gyp</code> runs, it will detect the specific release version of Node.js 516and download either the full source tarball or just the headers. If the full 517source is downloaded, addons will have complete access to the full set of 518Node.js dependencies. However, if only the Node.js headers are downloaded, 519then only the symbols exported by Node.js will be available.</p> 520</li> 521<li> 522<p><code>node-gyp</code> can be run using the <code>--nodedir</code> flag pointing at a local Node.js 523source image. Using this option, the addon will have access to the full set of 524dependencies.</p> 525</li> 526</ul> 527<h4>Loading addons using <code>require()</code><span><a class="mark" href="#addons_loading_addons_using_require" id="addons_loading_addons_using_require">#</a></span></h4> 528<p>The filename extension of the compiled addon binary is <code>.node</code> (as opposed 529to <code>.dll</code> or <code>.so</code>). The <a href="modules.html#modules_require_id"><code>require()</code></a> function is written to look for 530files with the <code>.node</code> file extension and initialize those as dynamically-linked 531libraries.</p> 532<p>When calling <a href="modules.html#modules_require_id"><code>require()</code></a>, the <code>.node</code> extension can usually be 533omitted and Node.js will still find and initialize the addon. One caveat, 534however, is that Node.js will first attempt to locate and load modules or 535JavaScript files that happen to share the same base name. For instance, if 536there is a file <code>addon.js</code> in the same directory as the binary <code>addon.node</code>, 537then <a href="modules.html#modules_require_id"><code>require('addon')</code></a> will give precedence to the <code>addon.js</code> file 538and load it instead.</p> 539</section><section><h3>Native abstractions for Node.js<span><a class="mark" href="#addons_native_abstractions_for_node_js" id="addons_native_abstractions_for_node_js">#</a></span></h3> 540<p>Each of the examples illustrated in this document directly use the 541Node.js and V8 APIs for implementing addons. The V8 API can, and has, changed 542dramatically from one V8 release to the next (and one major Node.js release to 543the next). With each change, addons may need to be updated and recompiled in 544order to continue functioning. The Node.js release schedule is designed to 545minimize the frequency and impact of such changes but there is little that 546Node.js can do to ensure stability of the V8 APIs.</p> 547<p>The <a href="https://github.com/nodejs/nan">Native Abstractions for Node.js</a> (or <code>nan</code>) provide a set of tools that 548addon developers are recommended to use to keep compatibility between past and 549future releases of V8 and Node.js. See the <code>nan</code> <a href="https://github.com/nodejs/nan/tree/HEAD/examples/">examples</a> for an 550illustration of how it can be used.</p> 551</section><section><h3>Node-API<span><a class="mark" href="#addons_node_api" id="addons_node_api">#</a></span></h3> 552<p></p><div class="api_stability api_stability_2"><a href="documentation.html#documentation_stability_index">Stability: 2</a> - Stable</div><p></p> 553<p>Node-API is an API for building native addons. It is independent from 554the underlying JavaScript runtime (e.g. V8) and is maintained as part of 555Node.js itself. This API will be Application Binary Interface (ABI) stable 556across versions of Node.js. It is intended to insulate addons from 557changes in the underlying JavaScript engine and allow modules 558compiled for one version to run on later versions of Node.js without 559recompilation. Addons are built/packaged with the same approach/tools 560outlined in this document (node-gyp, etc.). The only difference is the 561set of APIs that are used by the native code. Instead of using the V8 562or <a href="https://github.com/nodejs/nan">Native Abstractions for Node.js</a> APIs, the functions available 563in the Node-API are used.</p> 564<p>Creating and maintaining an addon that benefits from the ABI stability 565provided by Node-API carries with it certain 566<a href="n-api.html#n_api_implications_of_abi_stability">implementation considerations</a>.</p> 567<p>To use Node-API in the above "Hello world" example, replace the content of 568<code>hello.cc</code> with the following. All other instructions remain the same.</p> 569<pre><code class="language-cpp"><span class="hljs-comment">// hello.cc using Node-API</span> 570<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_api.h></span></span> 571 572<span class="hljs-keyword">namespace</span> demo { 573 574<span class="hljs-function">napi_value <span class="hljs-title">Method</span><span class="hljs-params">(napi_env env, napi_callback_info args)</span> </span>{ 575 napi_value greeting; 576 napi_status status; 577 578 status = <span class="hljs-built_in">napi_create_string_utf8</span>(env, <span class="hljs-string">"world"</span>, NAPI_AUTO_LENGTH, &greeting); 579 <span class="hljs-keyword">if</span> (status != napi_ok) <span class="hljs-keyword">return</span> <span class="hljs-literal">nullptr</span>; 580 <span class="hljs-keyword">return</span> greeting; 581} 582 583<span class="hljs-function">napi_value <span class="hljs-title">init</span><span class="hljs-params">(napi_env env, napi_value exports)</span> </span>{ 584 napi_status status; 585 napi_value fn; 586 587 status = <span class="hljs-built_in">napi_create_function</span>(env, <span class="hljs-literal">nullptr</span>, <span class="hljs-number">0</span>, Method, <span class="hljs-literal">nullptr</span>, &fn); 588 <span class="hljs-keyword">if</span> (status != napi_ok) <span class="hljs-keyword">return</span> <span class="hljs-literal">nullptr</span>; 589 590 status = <span class="hljs-built_in">napi_set_named_property</span>(env, exports, <span class="hljs-string">"hello"</span>, fn); 591 <span class="hljs-keyword">if</span> (status != napi_ok) <span class="hljs-keyword">return</span> <span class="hljs-literal">nullptr</span>; 592 <span class="hljs-keyword">return</span> exports; 593} 594 595<span class="hljs-built_in">NAPI_MODULE</span>(NODE_GYP_MODULE_NAME, init) 596 597} <span class="hljs-comment">// namespace demo</span></code></pre> 598<p>The functions available and how to use them are documented in 599<a href="n-api.html">C/C++ addons with Node-API</a>.</p> 600</section><section><h3>Addon examples<span><a class="mark" href="#addons_addon_examples" id="addons_addon_examples">#</a></span></h3> 601<p>Following are some example addons intended to help developers get started. The 602examples use the V8 APIs. Refer to the online <a href="https://v8docs.nodesource.com/">V8 reference</a> 603for help with the various V8 calls, and V8's <a href="https://github.com/v8/v8/wiki/Embedder's%20Guide">Embedder's Guide</a> for an 604explanation of several concepts used such as handles, scopes, function 605templates, etc.</p> 606<p>Each of these examples using the following <code>binding.gyp</code> file:</p> 607<pre><code class="language-json"><span class="hljs-punctuation">{</span> 608 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 609 <span class="hljs-punctuation">{</span> 610 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 611 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"addon.cc"</span> <span class="hljs-punctuation">]</span> 612 <span class="hljs-punctuation">}</span> 613 <span class="hljs-punctuation">]</span> 614<span class="hljs-punctuation">}</span></code></pre> 615<p>In cases where there is more than one <code>.cc</code> file, simply add the additional 616filename to the <code>sources</code> array:</p> 617<pre><code class="language-json"><span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"addon.cc"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"myexample.cc"</span><span class="hljs-punctuation">]</span></code></pre> 618<p>Once the <code>binding.gyp</code> file is ready, the example addons can be configured and 619built using <code>node-gyp</code>:</p> 620<pre><code class="language-console"><span class="hljs-meta">$ </span><span class="language-bash">node-gyp configure build</span></code></pre> 621<h4>Function arguments<span><a class="mark" href="#addons_function_arguments" id="addons_function_arguments">#</a></span></h4> 622<p>Addons will typically expose objects and functions that can be accessed from 623JavaScript running within Node.js. When functions are invoked from JavaScript, 624the input arguments and return value must be mapped to and from the C/C++ 625code.</p> 626<p>The following example illustrates how to read function arguments passed from 627JavaScript and how to return a result:</p> 628<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 629<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 630 631<span class="hljs-keyword">namespace</span> demo { 632 633<span class="hljs-keyword">using</span> v8::Exception; 634<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 635<span class="hljs-keyword">using</span> v8::Isolate; 636<span class="hljs-keyword">using</span> v8::Local; 637<span class="hljs-keyword">using</span> v8::Number; 638<span class="hljs-keyword">using</span> v8::Object; 639<span class="hljs-keyword">using</span> v8::String; 640<span class="hljs-keyword">using</span> v8::Value; 641 642<span class="hljs-comment">// This is the implementation of the "add" method</span> 643<span class="hljs-comment">// Input arguments are passed using the</span> 644<span class="hljs-comment">// const FunctionCallbackInfo<Value>& args struct</span> 645<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Add</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 646 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 647 648 <span class="hljs-comment">// Check the number of arguments passed.</span> 649 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">Length</span>() < <span class="hljs-number">2</span>) { 650 <span class="hljs-comment">// Throw an Error that is passed back to JavaScript</span> 651 isolate-><span class="hljs-built_in">ThrowException</span>(Exception::<span class="hljs-built_in">TypeError</span>( 652 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 653 <span class="hljs-string">"Wrong number of arguments"</span>).<span class="hljs-built_in">ToLocalChecked</span>())); 654 <span class="hljs-keyword">return</span>; 655 } 656 657 <span class="hljs-comment">// Check the argument types</span> 658 <span class="hljs-keyword">if</span> (!args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsNumber</span>() || !args[<span class="hljs-number">1</span>]-><span class="hljs-built_in">IsNumber</span>()) { 659 isolate-><span class="hljs-built_in">ThrowException</span>(Exception::<span class="hljs-built_in">TypeError</span>( 660 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 661 <span class="hljs-string">"Wrong arguments"</span>).<span class="hljs-built_in">ToLocalChecked</span>())); 662 <span class="hljs-keyword">return</span>; 663 } 664 665 <span class="hljs-comment">// Perform the operation</span> 666 <span class="hljs-type">double</span> value = 667 args[<span class="hljs-number">0</span>].<span class="hljs-built_in">As</span><Number>()-><span class="hljs-built_in">Value</span>() + args[<span class="hljs-number">1</span>].<span class="hljs-built_in">As</span><Number>()-><span class="hljs-built_in">Value</span>(); 668 Local<Number> num = Number::<span class="hljs-built_in">New</span>(isolate, value); 669 670 <span class="hljs-comment">// Set the return value (using the passed in</span> 671 <span class="hljs-comment">// FunctionCallbackInfo<Value>&)</span> 672 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(num); 673} 674 675<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 676 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"add"</span>, Add); 677} 678 679<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 680 681} <span class="hljs-comment">// namespace demo</span></code></pre> 682<p>Once compiled, the example addon can be required and used from within Node.js:</p> 683<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 684<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 685 686<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'This should be eight:'</span>, addon.<span class="hljs-title function_">add</span>(<span class="hljs-number">3</span>, <span class="hljs-number">5</span>));</code></pre> 687<h4>Callbacks<span><a class="mark" href="#addons_callbacks" id="addons_callbacks">#</a></span></h4> 688<p>It is common practice within addons to pass JavaScript functions to a C++ 689function and execute them from there. The following example illustrates how 690to invoke such callbacks:</p> 691<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 692<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 693 694<span class="hljs-keyword">namespace</span> demo { 695 696<span class="hljs-keyword">using</span> v8::Context; 697<span class="hljs-keyword">using</span> v8::Function; 698<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 699<span class="hljs-keyword">using</span> v8::Isolate; 700<span class="hljs-keyword">using</span> v8::Local; 701<span class="hljs-keyword">using</span> v8::Null; 702<span class="hljs-keyword">using</span> v8::Object; 703<span class="hljs-keyword">using</span> v8::String; 704<span class="hljs-keyword">using</span> v8::Value; 705 706<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">RunCallback</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 707 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 708 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 709 Local<Function> cb = Local<Function>::<span class="hljs-built_in">Cast</span>(args[<span class="hljs-number">0</span>]); 710 <span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> argc = <span class="hljs-number">1</span>; 711 Local<Value> argv[argc] = { 712 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 713 <span class="hljs-string">"hello world"</span>).<span class="hljs-built_in">ToLocalChecked</span>() }; 714 cb-><span class="hljs-built_in">Call</span>(context, <span class="hljs-built_in">Null</span>(isolate), argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 715} 716 717<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 718 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, RunCallback); 719} 720 721<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 722 723} <span class="hljs-comment">// namespace demo</span></code></pre> 724<p>This example uses a two-argument form of <code>Init()</code> that receives the full 725<code>module</code> object as the second argument. This allows the addon to completely 726overwrite <code>exports</code> with a single function instead of adding the function as a 727property of <code>exports</code>.</p> 728<p>To test it, run the following JavaScript:</p> 729<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 730<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 731 732<span class="hljs-title function_">addon</span>(<span class="hljs-function">(<span class="hljs-params">msg</span>) =></span> { 733 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(msg); 734<span class="hljs-comment">// Prints: 'hello world'</span> 735});</code></pre> 736<p>In this example, the callback function is invoked synchronously.</p> 737<h4>Object factory<span><a class="mark" href="#addons_object_factory" id="addons_object_factory">#</a></span></h4> 738<p>Addons can create and return new objects from within a C++ function as 739illustrated in the following example. An object is created and returned with a 740property <code>msg</code> that echoes the string passed to <code>createObject()</code>:</p> 741<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 742<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 743 744<span class="hljs-keyword">namespace</span> demo { 745 746<span class="hljs-keyword">using</span> v8::Context; 747<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 748<span class="hljs-keyword">using</span> v8::Isolate; 749<span class="hljs-keyword">using</span> v8::Local; 750<span class="hljs-keyword">using</span> v8::Object; 751<span class="hljs-keyword">using</span> v8::String; 752<span class="hljs-keyword">using</span> v8::Value; 753 754<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateObject</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 755 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 756 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 757 758 Local<Object> obj = Object::<span class="hljs-built_in">New</span>(isolate); 759 obj-><span class="hljs-built_in">Set</span>(context, 760 String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, 761 <span class="hljs-string">"msg"</span>).<span class="hljs-built_in">ToLocalChecked</span>(), 762 args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">ToString</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()) 763 .<span class="hljs-built_in">FromJust</span>(); 764 765 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(obj); 766} 767 768<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 769 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, CreateObject); 770} 771 772<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 773 774} <span class="hljs-comment">// namespace demo</span></code></pre> 775<p>To test it in JavaScript:</p> 776<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 777<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 778 779<span class="hljs-keyword">const</span> obj1 = <span class="hljs-title function_">addon</span>(<span class="hljs-string">'hello'</span>); 780<span class="hljs-keyword">const</span> obj2 = <span class="hljs-title function_">addon</span>(<span class="hljs-string">'world'</span>); 781<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj1.<span class="hljs-property">msg</span>, obj2.<span class="hljs-property">msg</span>); 782<span class="hljs-comment">// Prints: 'hello world'</span></code></pre> 783<h4>Function factory<span><a class="mark" href="#addons_function_factory" id="addons_function_factory">#</a></span></h4> 784<p>Another common scenario is creating JavaScript functions that wrap C++ 785functions and returning those back to JavaScript:</p> 786<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 787<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 788 789<span class="hljs-keyword">namespace</span> demo { 790 791<span class="hljs-keyword">using</span> v8::Context; 792<span class="hljs-keyword">using</span> v8::Function; 793<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 794<span class="hljs-keyword">using</span> v8::FunctionTemplate; 795<span class="hljs-keyword">using</span> v8::Isolate; 796<span class="hljs-keyword">using</span> v8::Local; 797<span class="hljs-keyword">using</span> v8::Object; 798<span class="hljs-keyword">using</span> v8::String; 799<span class="hljs-keyword">using</span> v8::Value; 800 801<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyFunction</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 802 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 803 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(String::<span class="hljs-built_in">NewFromUtf8</span>( 804 isolate, <span class="hljs-string">"hello world"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 805} 806 807<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateFunction</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 808 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 809 810 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 811 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, MyFunction); 812 Local<Function> fn = tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>(); 813 814 <span class="hljs-comment">// omit this to make it anonymous</span> 815 fn-><span class="hljs-built_in">SetName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>( 816 isolate, <span class="hljs-string">"theFunction"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 817 818 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(fn); 819} 820 821<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 822 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, CreateFunction); 823} 824 825<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, Init) 826 827} <span class="hljs-comment">// namespace demo</span></code></pre> 828<p>To test:</p> 829<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 830<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 831 832<span class="hljs-keyword">const</span> fn = <span class="hljs-title function_">addon</span>(); 833<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">fn</span>()); 834<span class="hljs-comment">// Prints: 'hello world'</span></code></pre> 835<h4>Wrapping C++ objects<span><a class="mark" href="#addons_wrapping_c_objects" id="addons_wrapping_c_objects">#</a></span></h4> 836<p>It is also possible to wrap C++ objects/classes in a way that allows new 837instances to be created using the JavaScript <code>new</code> operator:</p> 838<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 839<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 840<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 841 842<span class="hljs-keyword">namespace</span> demo { 843 844<span class="hljs-keyword">using</span> v8::Local; 845<span class="hljs-keyword">using</span> v8::Object; 846 847<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitAll</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 848 MyObject::<span class="hljs-built_in">Init</span>(exports); 849} 850 851<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, InitAll) 852 853} <span class="hljs-comment">// namespace demo</span></code></pre> 854<p>Then, in <code>myobject.h</code>, the wrapper class inherits from <code>node::ObjectWrap</code>:</p> 855<pre><code class="language-cpp"><span class="hljs-comment">// myobject.h</span> 856<span class="hljs-meta">#<span class="hljs-keyword">ifndef</span> MYOBJECT_H</span> 857<span class="hljs-meta">#<span class="hljs-keyword">define</span> MYOBJECT_H</span> 858 859<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 860<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 861 862<span class="hljs-keyword">namespace</span> demo { 863 864<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyObject</span> : <span class="hljs-keyword">public</span> node::ObjectWrap { 865 <span class="hljs-keyword">public</span>: 866 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(v8::Local<v8::Object> exports)</span></span>; 867 868 <span class="hljs-keyword">private</span>: 869 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">MyObject</span><span class="hljs-params">(<span class="hljs-type">double</span> value = <span class="hljs-number">0</span>)</span></span>; 870 ~<span class="hljs-built_in">MyObject</span>(); 871 872 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">New</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 873 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">PlusOne</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 874 875 <span class="hljs-type">double</span> value_; 876}; 877 878} <span class="hljs-comment">// namespace demo</span> 879 880<span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></code></pre> 881<p>In <code>myobject.cc</code>, implement the various methods that are to be exposed. 882Below, the method <code>plusOne()</code> is exposed by adding it to the constructor's 883prototype:</p> 884<pre><code class="language-cpp"><span class="hljs-comment">// myobject.cc</span> 885<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 886 887<span class="hljs-keyword">namespace</span> demo { 888 889<span class="hljs-keyword">using</span> v8::Context; 890<span class="hljs-keyword">using</span> v8::Function; 891<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 892<span class="hljs-keyword">using</span> v8::FunctionTemplate; 893<span class="hljs-keyword">using</span> v8::Isolate; 894<span class="hljs-keyword">using</span> v8::Local; 895<span class="hljs-keyword">using</span> v8::Number; 896<span class="hljs-keyword">using</span> v8::Object; 897<span class="hljs-keyword">using</span> v8::ObjectTemplate; 898<span class="hljs-keyword">using</span> v8::String; 899<span class="hljs-keyword">using</span> v8::Value; 900 901MyObject::<span class="hljs-built_in">MyObject</span>(<span class="hljs-type">double</span> value) : <span class="hljs-built_in">value_</span>(value) { 902} 903 904MyObject::~<span class="hljs-built_in">MyObject</span>() { 905} 906 907<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::Init</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 908 Isolate* isolate = exports-><span class="hljs-built_in">GetIsolate</span>(); 909 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 910 911 Local<ObjectTemplate> addon_data_tpl = ObjectTemplate::<span class="hljs-built_in">New</span>(isolate); 912 addon_data_tpl-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); <span class="hljs-comment">// 1 field for the MyObject::New()</span> 913 Local<Object> addon_data = 914 addon_data_tpl-><span class="hljs-built_in">NewInstance</span>(context).<span class="hljs-built_in">ToLocalChecked</span>(); 915 916 <span class="hljs-comment">// Prepare constructor template</span> 917 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, New, addon_data); 918 tpl-><span class="hljs-built_in">SetClassName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 919 tpl-><span class="hljs-built_in">InstanceTemplate</span>()-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); 920 921 <span class="hljs-comment">// Prototype</span> 922 <span class="hljs-built_in">NODE_SET_PROTOTYPE_METHOD</span>(tpl, <span class="hljs-string">"plusOne"</span>, PlusOne); 923 924 Local<Function> constructor = tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>(); 925 addon_data-><span class="hljs-built_in">SetInternalField</span>(<span class="hljs-number">0</span>, constructor); 926 exports-><span class="hljs-built_in">Set</span>(context, String::<span class="hljs-built_in">NewFromUtf8</span>( 927 isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>(), 928 constructor).<span class="hljs-built_in">FromJust</span>(); 929} 930 931<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::New</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 932 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 933 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 934 935 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">IsConstructCall</span>()) { 936 <span class="hljs-comment">// Invoked as constructor: `new MyObject(...)`</span> 937 <span class="hljs-type">double</span> value = args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsUndefined</span>() ? 938 <span class="hljs-number">0</span> : args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">NumberValue</span>(context).<span class="hljs-built_in">FromMaybe</span>(<span class="hljs-number">0</span>); 939 MyObject* obj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">MyObject</span>(value); 940 obj-><span class="hljs-built_in">Wrap</span>(args.<span class="hljs-built_in">This</span>()); 941 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(args.<span class="hljs-built_in">This</span>()); 942 } <span class="hljs-keyword">else</span> { 943 <span class="hljs-comment">// Invoked as plain function `MyObject(...)`, turn into construct call.</span> 944 <span class="hljs-keyword">const</span> <span class="hljs-type">int</span> argc = <span class="hljs-number">1</span>; 945 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 946 Local<Function> cons = 947 args.<span class="hljs-built_in">Data</span>().<span class="hljs-built_in">As</span><Object>()-><span class="hljs-built_in">GetInternalField</span>(<span class="hljs-number">0</span>).<span class="hljs-built_in">As</span><Function>(); 948 Local<Object> result = 949 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 950 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(result); 951 } 952} 953 954<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::PlusOne</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 955 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 956 957 MyObject* obj = ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>(args.<span class="hljs-built_in">Holder</span>()); 958 obj->value_ += <span class="hljs-number">1</span>; 959 960 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(Number::<span class="hljs-built_in">New</span>(isolate, obj->value_)); 961} 962 963} <span class="hljs-comment">// namespace demo</span></code></pre> 964<p>To build this example, the <code>myobject.cc</code> file must be added to the 965<code>binding.gyp</code>:</p> 966<pre><code class="language-json"><span class="hljs-punctuation">{</span> 967 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 968 <span class="hljs-punctuation">{</span> 969 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 970 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 971 <span class="hljs-string">"addon.cc"</span><span class="hljs-punctuation">,</span> 972 <span class="hljs-string">"myobject.cc"</span> 973 <span class="hljs-punctuation">]</span> 974 <span class="hljs-punctuation">}</span> 975 <span class="hljs-punctuation">]</span> 976<span class="hljs-punctuation">}</span></code></pre> 977<p>Test it with:</p> 978<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 979<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 980 981<span class="hljs-keyword">const</span> obj = <span class="hljs-keyword">new</span> addon.<span class="hljs-title class_">MyObject</span>(<span class="hljs-number">10</span>); 982<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 983<span class="hljs-comment">// Prints: 11</span> 984<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 985<span class="hljs-comment">// Prints: 12</span> 986<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 987<span class="hljs-comment">// Prints: 13</span></code></pre> 988<p>The destructor for a wrapper object will run when the object is 989garbage-collected. For destructor testing, there are command-line flags that 990can be used to make it possible to force garbage collection. These flags are 991provided by the underlying V8 JavaScript engine. They are subject to change 992or removal at any time. They are not documented by Node.js or V8, and they 993should never be used outside of testing.</p> 994<h4>Factory of wrapped objects<span><a class="mark" href="#addons_factory_of_wrapped_objects" id="addons_factory_of_wrapped_objects">#</a></span></h4> 995<p>Alternatively, it is possible to use a factory pattern to avoid explicitly 996creating object instances using the JavaScript <code>new</code> operator:</p> 997<pre><code class="language-js"><span class="hljs-keyword">const</span> obj = addon.<span class="hljs-title function_">createObject</span>(); 998<span class="hljs-comment">// instead of:</span> 999<span class="hljs-comment">// const obj = new addon.Object();</span></code></pre> 1000<p>First, the <code>createObject()</code> method is implemented in <code>addon.cc</code>:</p> 1001<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 1002<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1003<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1004 1005<span class="hljs-keyword">namespace</span> demo { 1006 1007<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1008<span class="hljs-keyword">using</span> v8::Isolate; 1009<span class="hljs-keyword">using</span> v8::Local; 1010<span class="hljs-keyword">using</span> v8::Object; 1011<span class="hljs-keyword">using</span> v8::String; 1012<span class="hljs-keyword">using</span> v8::Value; 1013 1014<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateObject</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1015 MyObject::<span class="hljs-built_in">NewInstance</span>(args); 1016} 1017 1018<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitAll</span><span class="hljs-params">(Local<Object> exports, Local<Object> <span class="hljs-keyword">module</span>)</span> </span>{ 1019 MyObject::<span class="hljs-built_in">Init</span>(exports-><span class="hljs-built_in">GetIsolate</span>()); 1020 1021 <span class="hljs-built_in">NODE_SET_METHOD</span>(<span class="hljs-keyword">module</span>, <span class="hljs-string">"exports"</span>, CreateObject); 1022} 1023 1024<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, InitAll) 1025 1026} <span class="hljs-comment">// namespace demo</span></code></pre> 1027<p>In <code>myobject.h</code>, the static method <code>NewInstance()</code> is added to handle 1028instantiating the object. This method takes the place of using <code>new</code> in 1029JavaScript:</p> 1030<pre><code class="language-cpp"><span class="hljs-comment">// myobject.h</span> 1031<span class="hljs-meta">#<span class="hljs-keyword">ifndef</span> MYOBJECT_H</span> 1032<span class="hljs-meta">#<span class="hljs-keyword">define</span> MYOBJECT_H</span> 1033 1034<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1035<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 1036 1037<span class="hljs-keyword">namespace</span> demo { 1038 1039<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyObject</span> : <span class="hljs-keyword">public</span> node::ObjectWrap { 1040 <span class="hljs-keyword">public</span>: 1041 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(v8::Isolate* isolate)</span></span>; 1042 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">NewInstance</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1043 1044 <span class="hljs-keyword">private</span>: 1045 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">MyObject</span><span class="hljs-params">(<span class="hljs-type">double</span> value = <span class="hljs-number">0</span>)</span></span>; 1046 ~<span class="hljs-built_in">MyObject</span>(); 1047 1048 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">New</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1049 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">PlusOne</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1050 <span class="hljs-keyword">static</span> v8::Global<v8::Function> constructor; 1051 <span class="hljs-type">double</span> value_; 1052}; 1053 1054} <span class="hljs-comment">// namespace demo</span> 1055 1056<span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></code></pre> 1057<p>The implementation in <code>myobject.cc</code> is similar to the previous example:</p> 1058<pre><code class="language-cpp"><span class="hljs-comment">// myobject.cc</span> 1059<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1060<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1061 1062<span class="hljs-keyword">namespace</span> demo { 1063 1064<span class="hljs-keyword">using</span> node::AddEnvironmentCleanupHook; 1065<span class="hljs-keyword">using</span> v8::Context; 1066<span class="hljs-keyword">using</span> v8::Function; 1067<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1068<span class="hljs-keyword">using</span> v8::FunctionTemplate; 1069<span class="hljs-keyword">using</span> v8::Global; 1070<span class="hljs-keyword">using</span> v8::Isolate; 1071<span class="hljs-keyword">using</span> v8::Local; 1072<span class="hljs-keyword">using</span> v8::Number; 1073<span class="hljs-keyword">using</span> v8::Object; 1074<span class="hljs-keyword">using</span> v8::String; 1075<span class="hljs-keyword">using</span> v8::Value; 1076 1077<span class="hljs-comment">// Warning! This is not thread-safe, this addon cannot be used for worker</span> 1078<span class="hljs-comment">// threads.</span> 1079Global<Function> MyObject::constructor; 1080 1081MyObject::<span class="hljs-built_in">MyObject</span>(<span class="hljs-type">double</span> value) : <span class="hljs-built_in">value_</span>(value) { 1082} 1083 1084MyObject::~<span class="hljs-built_in">MyObject</span>() { 1085} 1086 1087<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::Init</span><span class="hljs-params">(Isolate* isolate)</span> </span>{ 1088 <span class="hljs-comment">// Prepare constructor template</span> 1089 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, New); 1090 tpl-><span class="hljs-built_in">SetClassName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 1091 tpl-><span class="hljs-built_in">InstanceTemplate</span>()-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); 1092 1093 <span class="hljs-comment">// Prototype</span> 1094 <span class="hljs-built_in">NODE_SET_PROTOTYPE_METHOD</span>(tpl, <span class="hljs-string">"plusOne"</span>, PlusOne); 1095 1096 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1097 constructor.<span class="hljs-built_in">Reset</span>(isolate, tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1098 1099 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, [](<span class="hljs-type">void</span>*) { 1100 constructor.<span class="hljs-built_in">Reset</span>(); 1101 }, <span class="hljs-literal">nullptr</span>); 1102} 1103 1104<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::New</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1105 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1106 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1107 1108 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">IsConstructCall</span>()) { 1109 <span class="hljs-comment">// Invoked as constructor: `new MyObject(...)`</span> 1110 <span class="hljs-type">double</span> value = args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsUndefined</span>() ? 1111 <span class="hljs-number">0</span> : args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">NumberValue</span>(context).<span class="hljs-built_in">FromMaybe</span>(<span class="hljs-number">0</span>); 1112 MyObject* obj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">MyObject</span>(value); 1113 obj-><span class="hljs-built_in">Wrap</span>(args.<span class="hljs-built_in">This</span>()); 1114 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(args.<span class="hljs-built_in">This</span>()); 1115 } <span class="hljs-keyword">else</span> { 1116 <span class="hljs-comment">// Invoked as plain function `MyObject(...)`, turn into construct call.</span> 1117 <span class="hljs-keyword">const</span> <span class="hljs-type">int</span> argc = <span class="hljs-number">1</span>; 1118 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1119 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1120 Local<Object> instance = 1121 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1122 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1123 } 1124} 1125 1126<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::NewInstance</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1127 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1128 1129 <span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> argc = <span class="hljs-number">1</span>; 1130 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1131 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1132 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1133 Local<Object> instance = 1134 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1135 1136 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1137} 1138 1139<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::PlusOne</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1140 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1141 1142 MyObject* obj = ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>(args.<span class="hljs-built_in">Holder</span>()); 1143 obj->value_ += <span class="hljs-number">1</span>; 1144 1145 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(Number::<span class="hljs-built_in">New</span>(isolate, obj->value_)); 1146} 1147 1148} <span class="hljs-comment">// namespace demo</span></code></pre> 1149<p>Once again, to build this example, the <code>myobject.cc</code> file must be added to the 1150<code>binding.gyp</code>:</p> 1151<pre><code class="language-json"><span class="hljs-punctuation">{</span> 1152 <span class="hljs-attr">"targets"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 1153 <span class="hljs-punctuation">{</span> 1154 <span class="hljs-attr">"target_name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"addon"</span><span class="hljs-punctuation">,</span> 1155 <span class="hljs-attr">"sources"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> 1156 <span class="hljs-string">"addon.cc"</span><span class="hljs-punctuation">,</span> 1157 <span class="hljs-string">"myobject.cc"</span> 1158 <span class="hljs-punctuation">]</span> 1159 <span class="hljs-punctuation">}</span> 1160 <span class="hljs-punctuation">]</span> 1161<span class="hljs-punctuation">}</span></code></pre> 1162<p>Test it with:</p> 1163<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 1164<span class="hljs-keyword">const</span> createObject = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 1165 1166<span class="hljs-keyword">const</span> obj = <span class="hljs-title function_">createObject</span>(<span class="hljs-number">10</span>); 1167<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1168<span class="hljs-comment">// Prints: 11</span> 1169<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1170<span class="hljs-comment">// Prints: 12</span> 1171<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-title function_">plusOne</span>()); 1172<span class="hljs-comment">// Prints: 13</span> 1173 1174<span class="hljs-keyword">const</span> obj2 = <span class="hljs-title function_">createObject</span>(<span class="hljs-number">20</span>); 1175<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj2.<span class="hljs-title function_">plusOne</span>()); 1176<span class="hljs-comment">// Prints: 21</span> 1177<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj2.<span class="hljs-title function_">plusOne</span>()); 1178<span class="hljs-comment">// Prints: 22</span> 1179<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj2.<span class="hljs-title function_">plusOne</span>()); 1180<span class="hljs-comment">// Prints: 23</span></code></pre> 1181<h4>Passing wrapped objects around<span><a class="mark" href="#addons_passing_wrapped_objects_around" id="addons_passing_wrapped_objects_around">#</a></span></h4> 1182<p>In addition to wrapping and returning C++ objects, it is possible to pass 1183wrapped objects around by unwrapping them with the Node.js helper function 1184<code>node::ObjectWrap::Unwrap</code>. The following examples shows a function <code>add()</code> 1185that can take two <code>MyObject</code> objects as input arguments:</p> 1186<pre><code class="language-cpp"><span class="hljs-comment">// addon.cc</span> 1187<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1188<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 1189<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1190 1191<span class="hljs-keyword">namespace</span> demo { 1192 1193<span class="hljs-keyword">using</span> v8::Context; 1194<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1195<span class="hljs-keyword">using</span> v8::Isolate; 1196<span class="hljs-keyword">using</span> v8::Local; 1197<span class="hljs-keyword">using</span> v8::Number; 1198<span class="hljs-keyword">using</span> v8::Object; 1199<span class="hljs-keyword">using</span> v8::String; 1200<span class="hljs-keyword">using</span> v8::Value; 1201 1202<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CreateObject</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1203 MyObject::<span class="hljs-built_in">NewInstance</span>(args); 1204} 1205 1206<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Add</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1207 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1208 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1209 1210 MyObject* obj1 = node::ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>( 1211 args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">ToObject</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1212 MyObject* obj2 = node::ObjectWrap::<span class="hljs-built_in">Unwrap</span><MyObject>( 1213 args[<span class="hljs-number">1</span>]-><span class="hljs-built_in">ToObject</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1214 1215 <span class="hljs-type">double</span> sum = obj1-><span class="hljs-built_in">value</span>() + obj2-><span class="hljs-built_in">value</span>(); 1216 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(Number::<span class="hljs-built_in">New</span>(isolate, sum)); 1217} 1218 1219<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">InitAll</span><span class="hljs-params">(Local<Object> exports)</span> </span>{ 1220 MyObject::<span class="hljs-built_in">Init</span>(exports-><span class="hljs-built_in">GetIsolate</span>()); 1221 1222 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"createObject"</span>, CreateObject); 1223 <span class="hljs-built_in">NODE_SET_METHOD</span>(exports, <span class="hljs-string">"add"</span>, Add); 1224} 1225 1226<span class="hljs-built_in">NODE_MODULE</span>(NODE_GYP_MODULE_NAME, InitAll) 1227 1228} <span class="hljs-comment">// namespace demo</span></code></pre> 1229<p>In <code>myobject.h</code>, a new public method is added to allow access to private values 1230after unwrapping the object.</p> 1231<pre><code class="language-cpp"><span class="hljs-comment">// myobject.h</span> 1232<span class="hljs-meta">#<span class="hljs-keyword">ifndef</span> MYOBJECT_H</span> 1233<span class="hljs-meta">#<span class="hljs-keyword">define</span> MYOBJECT_H</span> 1234 1235<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1236<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node_object_wrap.h></span></span> 1237 1238<span class="hljs-keyword">namespace</span> demo { 1239 1240<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyObject</span> : <span class="hljs-keyword">public</span> node::ObjectWrap { 1241 <span class="hljs-keyword">public</span>: 1242 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">Init</span><span class="hljs-params">(v8::Isolate* isolate)</span></span>; 1243 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">NewInstance</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1244 <span class="hljs-function"><span class="hljs-keyword">inline</span> <span class="hljs-type">double</span> <span class="hljs-title">value</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> </span>{ <span class="hljs-keyword">return</span> value_; } 1245 1246 <span class="hljs-keyword">private</span>: 1247 <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">MyObject</span><span class="hljs-params">(<span class="hljs-type">double</span> value = <span class="hljs-number">0</span>)</span></span>; 1248 ~<span class="hljs-built_in">MyObject</span>(); 1249 1250 <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-type">void</span> <span class="hljs-title">New</span><span class="hljs-params">(<span class="hljs-keyword">const</span> v8::FunctionCallbackInfo<v8::Value>& args)</span></span>; 1251 <span class="hljs-keyword">static</span> v8::Global<v8::Function> constructor; 1252 <span class="hljs-type">double</span> value_; 1253}; 1254 1255} <span class="hljs-comment">// namespace demo</span> 1256 1257<span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></code></pre> 1258<p>The implementation of <code>myobject.cc</code> is similar to before:</p> 1259<pre><code class="language-cpp"><span class="hljs-comment">// myobject.cc</span> 1260<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node.h></span></span> 1261<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"myobject.h"</span></span> 1262 1263<span class="hljs-keyword">namespace</span> demo { 1264 1265<span class="hljs-keyword">using</span> node::AddEnvironmentCleanupHook; 1266<span class="hljs-keyword">using</span> v8::Context; 1267<span class="hljs-keyword">using</span> v8::Function; 1268<span class="hljs-keyword">using</span> v8::FunctionCallbackInfo; 1269<span class="hljs-keyword">using</span> v8::FunctionTemplate; 1270<span class="hljs-keyword">using</span> v8::Global; 1271<span class="hljs-keyword">using</span> v8::Isolate; 1272<span class="hljs-keyword">using</span> v8::Local; 1273<span class="hljs-keyword">using</span> v8::Object; 1274<span class="hljs-keyword">using</span> v8::String; 1275<span class="hljs-keyword">using</span> v8::Value; 1276 1277<span class="hljs-comment">// Warning! This is not thread-safe, this addon cannot be used for worker</span> 1278<span class="hljs-comment">// threads.</span> 1279Global<Function> MyObject::constructor; 1280 1281MyObject::<span class="hljs-built_in">MyObject</span>(<span class="hljs-type">double</span> value) : <span class="hljs-built_in">value_</span>(value) { 1282} 1283 1284MyObject::~<span class="hljs-built_in">MyObject</span>() { 1285} 1286 1287<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::Init</span><span class="hljs-params">(Isolate* isolate)</span> </span>{ 1288 <span class="hljs-comment">// Prepare constructor template</span> 1289 Local<FunctionTemplate> tpl = FunctionTemplate::<span class="hljs-built_in">New</span>(isolate, New); 1290 tpl-><span class="hljs-built_in">SetClassName</span>(String::<span class="hljs-built_in">NewFromUtf8</span>(isolate, <span class="hljs-string">"MyObject"</span>).<span class="hljs-built_in">ToLocalChecked</span>()); 1291 tpl-><span class="hljs-built_in">InstanceTemplate</span>()-><span class="hljs-built_in">SetInternalFieldCount</span>(<span class="hljs-number">1</span>); 1292 1293 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1294 constructor.<span class="hljs-built_in">Reset</span>(isolate, tpl-><span class="hljs-built_in">GetFunction</span>(context).<span class="hljs-built_in">ToLocalChecked</span>()); 1295 1296 <span class="hljs-built_in">AddEnvironmentCleanupHook</span>(isolate, [](<span class="hljs-type">void</span>*) { 1297 constructor.<span class="hljs-built_in">Reset</span>(); 1298 }, <span class="hljs-literal">nullptr</span>); 1299} 1300 1301<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::New</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1302 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1303 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1304 1305 <span class="hljs-keyword">if</span> (args.<span class="hljs-built_in">IsConstructCall</span>()) { 1306 <span class="hljs-comment">// Invoked as constructor: `new MyObject(...)`</span> 1307 <span class="hljs-type">double</span> value = args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">IsUndefined</span>() ? 1308 <span class="hljs-number">0</span> : args[<span class="hljs-number">0</span>]-><span class="hljs-built_in">NumberValue</span>(context).<span class="hljs-built_in">FromMaybe</span>(<span class="hljs-number">0</span>); 1309 MyObject* obj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">MyObject</span>(value); 1310 obj-><span class="hljs-built_in">Wrap</span>(args.<span class="hljs-built_in">This</span>()); 1311 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(args.<span class="hljs-built_in">This</span>()); 1312 } <span class="hljs-keyword">else</span> { 1313 <span class="hljs-comment">// Invoked as plain function `MyObject(...)`, turn into construct call.</span> 1314 <span class="hljs-keyword">const</span> <span class="hljs-type">int</span> argc = <span class="hljs-number">1</span>; 1315 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1316 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1317 Local<Object> instance = 1318 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1319 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1320 } 1321} 1322 1323<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyObject::NewInstance</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FunctionCallbackInfo<Value>& args)</span> </span>{ 1324 Isolate* isolate = args.<span class="hljs-built_in">GetIsolate</span>(); 1325 1326 <span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> argc = <span class="hljs-number">1</span>; 1327 Local<Value> argv[argc] = { args[<span class="hljs-number">0</span>] }; 1328 Local<Function> cons = Local<Function>::<span class="hljs-built_in">New</span>(isolate, constructor); 1329 Local<Context> context = isolate-><span class="hljs-built_in">GetCurrentContext</span>(); 1330 Local<Object> instance = 1331 cons-><span class="hljs-built_in">NewInstance</span>(context, argc, argv).<span class="hljs-built_in">ToLocalChecked</span>(); 1332 1333 args.<span class="hljs-built_in">GetReturnValue</span>().<span class="hljs-built_in">Set</span>(instance); 1334} 1335 1336} <span class="hljs-comment">// namespace demo</span></code></pre> 1337<p>Test it with:</p> 1338<pre><code class="language-js"><span class="hljs-comment">// test.js</span> 1339<span class="hljs-keyword">const</span> addon = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./build/Release/addon'</span>); 1340 1341<span class="hljs-keyword">const</span> obj1 = addon.<span class="hljs-title function_">createObject</span>(<span class="hljs-number">10</span>); 1342<span class="hljs-keyword">const</span> obj2 = addon.<span class="hljs-title function_">createObject</span>(<span class="hljs-number">20</span>); 1343<span class="hljs-keyword">const</span> result = addon.<span class="hljs-title function_">add</span>(obj1, obj2); 1344 1345<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(result); 1346<span class="hljs-comment">// Prints: 30</span></code></pre></section> 1347 <!-- API END --> 1348 </div> 1349 </div> 1350 </div> 1351 <script> 1352 'use strict'; 1353 { 1354 const kCustomPreference = 'customDarkTheme'; 1355 const userSettings = sessionStorage.getItem(kCustomPreference); 1356 const themeToggleButton = document.getElementById('theme-toggle-btn'); 1357 if (userSettings === null && window.matchMedia) { 1358 const mq = window.matchMedia('(prefers-color-scheme: dark)'); 1359 if ('onchange' in mq) { 1360 function mqChangeListener(e) { 1361 document.body.classList.toggle('dark-mode', e.matches); 1362 } 1363 mq.addEventListener('change', mqChangeListener); 1364 if (themeToggleButton) { 1365 themeToggleButton.addEventListener('click', function() { 1366 mq.removeEventListener('change', mqChangeListener); 1367 }, { once: true }); 1368 } 1369 } 1370 if (mq.matches) { 1371 document.body.classList.add('dark-mode'); 1372 } 1373 } else if (userSettings === 'true') { 1374 document.body.classList.add('dark-mode'); 1375 } 1376 if (themeToggleButton) { 1377 themeToggleButton.hidden = false; 1378 themeToggleButton.addEventListener('click', function() { 1379 sessionStorage.setItem( 1380 kCustomPreference, 1381 document.body.classList.toggle('dark-mode') 1382 ); 1383 }); 1384 } 1385 } 1386 </script> 1387</body> 1388</html> 1389