Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
integrating-with-js-values-from-cpp.qdoc
Go to the documentation of this file.
1
// Copyright (C) 2012 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
/*!
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.
7
8
The following classes can be used to load and access JavaSript from C++ code:
9
10
\list
11
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.
16
\endlist
17
18
Use QJSValue to transfer values to and from the engine, and use QJSManagedValue
19
to interact with JavaScript values. Only use QJSPrimitiveValues if you have to
20
emulate the semantics of JS primitive values in C++.
21
22
\table
23
\header
24
\li QJSValue
25
\li QJSManagedValue
26
\li QJSPrimitiveValue
27
\row
28
\li Persistently store values
29
\li Short lived
30
\li Short lived
31
\row
32
\li Transport values to/from engine
33
\li Access properties
34
\li Only Primitives
35
\row
36
\li
37
\li Call methods
38
\li Basic arithmetic and comparison
39
\endtable
40
41
\section1 QJSValue as a Container Type
42
43
\l QJSValue stores the Qt/JavaScript data types supported in ECMAScript including
44
function, array and arbitrary object types as well as anything supported by
45
QVariant. As a container, it can be used to pass values to and receive values
46
from a QJSEngine.
47
48
\snippet qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp qjs-as-container
49
50
In case of a cache miss, \c undefined is returned. Otherwise, the cached value is
51
returned. Note that implicit conversions (from QString and QJSValue::SpecialValue respectively)
52
occur when the value is returned.
53
54
QJSValue also has an API to interact with the contained value, but using
55
QJSManagedValue is recommended.
56
57
\section1 Primitive and Managed Values
58
59
QJSValue and QJSManagedValue store values that can be either managed or primitive.
60
In QML’s JS engine, a managed value can be thought of as a pointer to some data
61
structure on the heap, whose memory is managed by the engine’s garbage collector.
62
The actual content of primitive values is stored directly, using a technique
63
called NaN-boxing that enables you to represent a NaN-value in multiple ways, even
64
though only two are actually needed; one for signalling and one for quiet NaN-value.
65
66
\table
67
\header
68
\li Primitive Values
69
\li Managed Values
70
\row
71
\li int
72
\li Function
73
\row
74
\li double
75
\li Array
76
\row
77
\li undefined
78
\li QVariant
79
\row
80
\li null
81
\li string object
82
\row
83
\li QString
84
\li
85
\endtable
86
87
A pointer to the engine can be obtained from a managed value, but not from a
88
primitive one. When using QJSValue for its JavaScript API, you need access
89
to the engine to evaluate JavaScript. For example, to run the \c call(args) function,
90
you have to interpret it in the engine. This works, as the function is a managed
91
value, and you can obtain the engine from it.
92
93
Similarly, where the engine is needed when you call a function or
94
access a property on a primitive number or string. Whenever you call a method on
95
a primitive, an instance of its corresponding non-primitive objects is created.
96
This is referred as boxing. When you write \c (42).constructor, that is equivalent
97
to \c (new Number(42)).constructor, and it returns the constructor method of the
98
global number object. Accordingly, if you write \c QJSValue(42).property("constructor"),
99
you would expect to obtain a QJSValue containing that function. However, what you
100
get is instead a QJSValue containing \c undefined.
101
102
The QJSValue that you constructed contains only a primitive value, and thus you have
103
no way to access the engine. You also can’t simply hardcode the property lookup
104
for primitive values in QJSEngine, as in one engine you might set
105
\e {Number.prototype.constructor.additionalProperty = "the Spanish Inquisition"}
106
whereas in another \e {Number.prototype.constructor.additionalProperty = 42}.
107
The end result would then clearly be unexpected.
108
109
To ensure that property accesses always work, you would need to always store boxed
110
values in QJSValue or store an additional pointer to the engine.
111
112
However, this would be incompatible with how QJSValue is currently used, lead to
113
pointless JS heap allocations when passing around primitives, and increase the
114
size needed to store a QJSValue. Therefore, you should use \l QJSValue only for
115
storage and \l QJSManagedValue to obtain the engine.
116
117
\section1 QJSManagedValue
118
119
QJSManagedValue is similar to QJSValue, with a few differences:
120
121
\list
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.
127
\endlist
128
129
To obtain the engine in code, either you are in a scripting context where you’ve
130
already got access to an engine to create new objects with \c QJSEngine::newObject
131
and to evaluate expressions with \c QJSEngine::evaluate, or you want to evaluate
132
some JavaScript in a QObject that has been registered with the engine. In the
133
latter case, you can use \c qjsEngine(this) to obtain the currently active
134
QJSEngine.
135
136
QJSManagedValue also provides a few methods that have no equivalent in QJSEngine.
137
138
In the example below, QJSManagedValue methods encounter an exception, and
139
QJSEngine::catchError is used to handle the exception.
140
141
\snippet qtjavascript/integratingjswithcpp/exampleqjsengine.cpp qjs-engine-example
142
143
However, inside a method of a registered object, you might want to instead let
144
the exception bubble up the call stack.
145
146
QJSManagedValue should be temporarily created on the stack,
147
and discarded once you don’t need to work any longer on the contained value.
148
Since QJSValue can store primitive values in a more efficient way, QJSManagedValue
149
should also not be used as an interface type which is the return or parameter type of
150
functions, and the type of properties, as the engine does not treat it in a
151
special way, and will not convert values to it (in contrast to QJSValue).
152
153
\section1 QJSPrimitiveValue
154
155
\l QJSPrimitiveValue can store any of the primitive types, and supports arithmetic
156
operations and comparisons according to the ECMA-262 standard. It allows for
157
low-overhead operations on primitives in contrast to QJSManagedValue, which always goes
158
through the engine, while still yielding results that are indistinguishable
159
from what the engine would return. As QJSPrimitiveValue is comparatively large, it
160
is not recommended to store values.
161
162
*/
qtdeclarative
src
qml
doc
src
cppintegration
integrating-with-js-values-from-cpp.qdoc
Generated on
for Qt by
1.14.0