1// Copyright (C) 2012 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
4\page qtqml-integrating-with-js-values-from-cpp.html
5\title Integrating with JavaScript values from C++
6\brief Description of how to load and access JavaScript from C++ code.
8The following classes can be used to load and access JavaSript from C++ code:
12 \li \l QJSValue, which acts as a container for Qt/JavaScript data types.
13 \li \l QJSManagedValue, which represents a value on the JavaScript heap
14 belonging to a \l QJSEngine.
15 \li \l QJSPrimitiveValue, which operates on primitive types in JavaScript semantics.
18Use QJSValue to transfer values to and from the engine, and use QJSManagedValue
19to interact with JavaScript values. Only use QJSPrimitiveValues if you have to
20emulate the semantics of JS primitive values in C++.
28 \li Persistently store values
32 \li Transport values to/from engine
38 \li Basic arithmetic and comparison
41\section1 QJSValue as a Container Type
43\l QJSValue stores the Qt/JavaScript data types supported in ECMAScript including
44function, array and arbitrary object types as well as anything supported by
45QVariant. As a container, it can be used to pass values to and receive values
48\snippet qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp qjs-as-container
50In case of a cache miss, \c undefined is returned. Otherwise, the cached value is
51returned. Note that implicit conversions (from QString and QJSValue::SpecialValue respectively)
52occur when the value is returned.
54QJSValue also has an API to interact with the contained value, but using
55QJSManagedValue is recommended.
57\section1 Primitive and Managed Values
59QJSValue and QJSManagedValue store values that can be either managed or primitive.
60In QML’s JS engine, a managed value can be thought of as a pointer to some data
61structure on the heap, whose memory is managed by the engine’s garbage collector.
62The actual content of primitive values is stored directly, using a technique
63called NaN-boxing that enables you to represent a NaN-value in multiple ways, even
64though only two are actually needed; one for signalling and one for quiet NaN-value.
87A pointer to the engine can be obtained from a managed value, but not from a
88primitive one. When using QJSValue for its JavaScript API, you need access
89to the engine to evaluate JavaScript. For example, to run the \c call(args) function,
90you have to interpret it in the engine. This works, as the function is a managed
91value, and you can obtain the engine from it.
93Similarly, where the engine is needed when you call a function or
94access a property on a primitive number or string. Whenever you call a method on
95a primitive, an instance of its corresponding non-primitive objects is created.
96This is referred as boxing. When you write \c (42).constructor, that is equivalent
97to \c (new Number(42)).constructor, and it returns the constructor method of the
98global number object. Accordingly, if you write \c QJSValue(42).property("constructor"),
99you would expect to obtain a QJSValue containing that function. However, what you
100get is instead a QJSValue containing \c undefined.
102The QJSValue that you constructed contains only a primitive value, and thus you have
103no way to access the engine. You also can’t simply hardcode the property lookup
104for primitive values in QJSEngine, as in one engine you might set
105\e {Number.prototype.constructor.additionalProperty = "the Spanish Inquisition"}
106whereas in another \e {Number.prototype.constructor.additionalProperty = 42}.
107The end result would then clearly be unexpected.
109To ensure that property accesses always work, you would need to always store boxed
110values in QJSValue or store an additional pointer to the engine.
112However, this would be incompatible with how QJSValue is currently used, lead to
113pointless JS heap allocations when passing around primitives, and increase the
114size needed to store a QJSValue. Therefore, you should use \l QJSValue only for
115storage and \l QJSManagedValue to obtain the engine.
117\section1 QJSManagedValue
119QJSManagedValue is similar to QJSValue, with a few differences:
122\li The constructors (except for the default and move constructor2) require
123 passing a QJSEngine pointer.
124\li Methods like \l {QJSManagedValue::}{deleteProperty} and
125 \l {QJSManagedValue::}{isSymbol} are added.
126\li If QJSManagedValue methods encounter an exception, they leave it intact.
129To obtain the engine in code, either you are in a scripting context where you’ve
130already got access to an engine to create new objects with \c QJSEngine::newObject
131and to evaluate expressions with \c QJSEngine::evaluate, or you want to evaluate
132some JavaScript in a QObject that has been registered with the engine. In the
133latter case, you can use \c qjsEngine(this) to obtain the currently active
136QJSManagedValue also provides a few methods that have no equivalent in QJSEngine.
138In the example below, QJSManagedValue methods encounter an exception, and
139QJSEngine::catchError is used to handle the exception.
141\snippet qtjavascript/integratingjswithcpp/exampleqjsengine.cpp qjs-engine-example
143However, inside a method of a registered object, you might want to instead let
144the exception bubble up the call stack.
146QJSManagedValue should be temporarily created on the stack,
147and discarded once you don’t need to work any longer on the contained value.
148Since QJSValue can store primitive values in a more efficient way, QJSManagedValue
149should also not be used as an interface type which is the return or parameter type of
150functions, and the type of properties, as the engine does not treat it in a
151special way, and will not convert values to it (in contrast to QJSValue).
153\section1 QJSPrimitiveValue
155\l QJSPrimitiveValue can store any of the primitive types, and supports arithmetic
156operations and comparisons according to the ECMA-262 standard. It allows for
157low-overhead operations on primitives in contrast to QJSManagedValue, which always goes
158through the engine, while still yielding results that are indistinguishable
159from what the engine would return. As QJSPrimitiveValue is comparatively large, it
160is not recommended to store values.