1 | // Copyright (C) 2016 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include <QtCore/qstring.h> |
5 | #include <QtCore/qvarlengtharray.h> |
6 | #include <QtCore/qdatetime.h> |
7 | #include "qjsvalue.h" |
8 | #include "qjsprimitivevalue.h" |
9 | #include "qjsmanagedvalue.h" |
10 | #include "qjsvalue_p.h" |
11 | #include "qv4value_p.h" |
12 | #include "qv4object_p.h" |
13 | #include "qv4functionobject_p.h" |
14 | #include "qv4dateobject_p.h" |
15 | #include "qv4runtime_p.h" |
16 | #include "qv4variantobject_p.h" |
17 | #include "qv4regexpobject_p.h" |
18 | #include "qv4errorobject_p.h" |
19 | #include <private/qv4mm_p.h> |
20 | #include <private/qv4jscall_p.h> |
21 | #include <private/qv4qobjectwrapper_p.h> |
22 | #include <private/qv4qmetaobjectwrapper_p.h> |
23 | #include <private/qv4urlobject_p.h> |
24 | #include <private/qqmlbuiltins_p.h> |
25 | |
26 | /*! |
27 | \since 5.0 |
28 | \class QJSValue |
29 | |
30 | \brief The QJSValue class acts as a container for Qt/JavaScript data types. |
31 | |
32 | \ingroup qtjavascript |
33 | \inmodule QtQml |
34 | |
35 | QJSValue supports the types defined in the \l{ECMA-262} |
36 | standard: The primitive types, which are Undefined, Null, Boolean, |
37 | Number, and String; and the Object and Array types. Additionally, built-in |
38 | support is provided for Qt/C++ types such as QVariant and QObject. |
39 | |
40 | For the object-based types (including Date and RegExp), use the |
41 | newT() functions in QJSEngine (e.g. QJSEngine::newObject()) |
42 | to create a QJSValue of the desired type. For the primitive types, |
43 | use one of the QJSValue constructor overloads. For other types, e.g. |
44 | registered gadget types such as QPoint, you can use QJSEngine::toScriptValue. |
45 | |
46 | The methods named isT() (e.g. isBool(), isUndefined()) can be |
47 | used to test if a value is of a certain type. The methods named |
48 | toT() (e.g. toBool(), toString()) can be used to convert a |
49 | QJSValue to another type. You can also use the generic |
50 | qjsvalue_cast() function. |
51 | |
52 | Object values have zero or more properties which are themselves |
53 | QJSValues. Use setProperty() to set a property of an object, and |
54 | call property() to retrieve the value of a property. |
55 | |
56 | \snippet code/src_script_qjsvalue.cpp 0 |
57 | |
58 | If you want to iterate over the properties of a script object, use |
59 | the QJSValueIterator class. |
60 | |
61 | Object values have an internal \c{prototype} property, which can be |
62 | accessed with prototype() and setPrototype(). |
63 | |
64 | Function objects (objects for which isCallable()) returns true) can |
65 | be invoked by calling call(). Constructor functions can be used to |
66 | construct new objects by calling callAsConstructor(). |
67 | |
68 | Use equals() or strictlyEquals() to compare a QJSValue to another. |
69 | |
70 | Note that a QJSValue for which isObject() is true only carries a |
71 | reference to an actual object; copying the QJSValue will only |
72 | copy the object reference, not the object itself. If you want to |
73 | clone an object (i.e. copy an object's properties to another |
74 | object), you can do so with the help of a \c{for-in} statement in |
75 | script code, or QJSValueIterator in C++. |
76 | |
77 | \sa QJSEngine, QJSValueIterator |
78 | |
79 | \section1 Working With Arrays |
80 | |
81 | To create an array using QJSValue, use \l QJSEngine::newArray(): |
82 | |
83 | \code |
84 | // Assumes that this class was declared in QML. |
85 | QJSValue jsArray = engine->newArray(3); |
86 | \endcode |
87 | |
88 | To set individual elements in the array, use |
89 | the \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)} |
90 | overload. For example, to fill the array above with integers: |
91 | |
92 | \code |
93 | for (int i = 0; i < 3; ++i) { |
94 | jsArray.setProperty(i, QRandomGenerator::global().generate()); |
95 | } |
96 | \endcode |
97 | |
98 | To determine the length of the array, access the \c "length" property. |
99 | To access array elements, use the |
100 | \l {QJSValue::}{property(quint32 arrayIndex)} overload. The following code |
101 | reads the array we created above back into a list: |
102 | |
103 | \code |
104 | QVector<int> integers; |
105 | const int length = jsArray.property("length").toInt(); |
106 | for (int i = 0; i < length; ++i) { |
107 | integers.append(jsArray.property(i).toInt()); |
108 | } |
109 | \endcode |
110 | |
111 | \section2 Converting to JSON |
112 | |
113 | It's possible to convert a QJSValue to a JSON type. For example, |
114 | to convert to an array, use \l QJSEngine::fromScriptValue(): |
115 | |
116 | \code |
117 | const QJsonValue jsonValue = engine.fromScriptValue<QJsonValue>(jsValue); |
118 | const QJsonArray jsonArray = jsonValue.toArray(); |
119 | \endcode |
120 | */ |
121 | |
122 | /*! |
123 | \enum QJSValue::SpecialValue |
124 | |
125 | This enum is used to specify a single-valued type. |
126 | |
127 | \value UndefinedValue An undefined value. |
128 | |
129 | \value NullValue A null value. |
130 | */ |
131 | |
132 | /*! |
133 | \typedef QJSValueList |
134 | \relates QJSValue |
135 | |
136 | This is a typedef for a QList<QJSValue>. |
137 | */ |
138 | |
139 | /*! |
140 | \enum QJSValue::ErrorType |
141 | \since 5.12 |
142 | |
143 | Use this enum for JavaScript language-specific types of Error objects. |
144 | |
145 | They may be useful when emulating language features in C++ requires the use |
146 | of specialized exception types. In addition, they may help to more clearly |
147 | communicate certain typical conditions, instead of throwing a generic |
148 | JavaScript exception. For example, code that deals with networking and |
149 | resource locators may find it useful to propagate errors related to |
150 | malformed locators using the URIError type. |
151 | |
152 | \omitvalue NoError |
153 | \value GenericError A generic Error object, but not of a specific sub-type. |
154 | \omitvalue EvalError |
155 | \value RangeError A value did not match the expected set or range. |
156 | \value ReferenceError A non-existing variable referenced. |
157 | \value SyntaxError An invalid token or sequence of tokens was encountered |
158 | that does not conform with the syntax of the language. |
159 | \value TypeError An operand or argument is incompatible with the type |
160 | expected. |
161 | \value URIError A URI handling function was used incorrectly or the URI |
162 | provided is malformed. |
163 | */ |
164 | |
165 | /*! |
166 | \enum QJSValue::ObjectConversionBehavior |
167 | |
168 | This enum is used to specify how JavaScript objects and symbols without an equivalent |
169 | native Qt type should be treated when converting to QVariant. |
170 | |
171 | \value ConvertJSObjects A best-effort, possibly lossy, conversion is attempted. |
172 | Symbols are converted to QString. |
173 | |
174 | \value RetainJSObjects The value is retained as QJSValue wrapped in QVariant. |
175 | */ |
176 | |
177 | QT_BEGIN_NAMESPACE |
178 | |
179 | using namespace QV4; |
180 | |
181 | /*! |
182 | Constructs a new QJSValue with a boolean \a value. |
183 | */ |
184 | QJSValue::QJSValue(bool value) : d(QJSValuePrivate::encode(boolValue: value)) |
185 | { |
186 | } |
187 | |
188 | /*! |
189 | Constructs a new QJSValue with a number \a value. |
190 | */ |
191 | QJSValue::QJSValue(int value) : d(QJSValuePrivate::encode(intValue: value)) |
192 | { |
193 | } |
194 | |
195 | /*! |
196 | Constructs a new QJSValue with a number \a value. |
197 | */ |
198 | QJSValue::QJSValue(uint value) : d(QJSValuePrivate::encode(uintValue: value)) |
199 | { |
200 | } |
201 | |
202 | /*! |
203 | Constructs a new QJSValue with a number \a value. |
204 | */ |
205 | QJSValue::QJSValue(double value) : d(QJSValuePrivate::encode(doubleValue: value)) |
206 | { |
207 | } |
208 | |
209 | /*! |
210 | Constructs a new QJSValue with a string \a value. |
211 | */ |
212 | QJSValue::QJSValue(const QString &value) : d(QJSValuePrivate::encode(stringValue: value)) |
213 | { |
214 | } |
215 | |
216 | /*! |
217 | Constructs a new QJSValue with a special \a value. |
218 | */ |
219 | QJSValue::QJSValue(SpecialValue value) |
220 | : d(value == NullValue ? QJSValuePrivate::encodeNull() : QJSValuePrivate::encodeUndefined()) |
221 | { |
222 | } |
223 | |
224 | /*! |
225 | Constructs a new QJSValue with a string \a value. |
226 | */ |
227 | QJSValue::QJSValue(const QLatin1String &value) : d(QJSValuePrivate::encode(stringValue: value)) |
228 | { |
229 | } |
230 | |
231 | /*! |
232 | Constructs a new QJSValue with a string \a value. |
233 | */ |
234 | #ifndef QT_NO_CAST_FROM_ASCII |
235 | QJSValue::QJSValue(const char *value) : d(QJSValuePrivate::encode(stringValue: QString::fromUtf8(utf8: value))) |
236 | { |
237 | } |
238 | #endif |
239 | |
240 | /*! |
241 | Constructs a new QJSValue that is a copy of \a other. |
242 | |
243 | Note that if \a other is an object (i.e., isObject() would return |
244 | true), then only a reference to the underlying object is copied into |
245 | the new script value (i.e., the object itself is not copied). |
246 | */ |
247 | QJSValue::QJSValue(const QJSValue &other) : d(other.d) |
248 | { |
249 | switch (QJSValuePrivate::tag(raw: d)) { |
250 | case QJSValuePrivate::Kind::Undefined: |
251 | case QJSValuePrivate::Kind::Null: |
252 | case QJSValuePrivate::Kind::IntValue: |
253 | case QJSValuePrivate::Kind::BoolValue: |
254 | return; |
255 | case QJSValuePrivate::Kind::DoublePtr: |
256 | d = QJSValuePrivate::encode(doubleValue: *QJSValuePrivate::doublePtr(v: d)); |
257 | return; |
258 | case QJSValuePrivate::Kind::QV4ValuePtr: |
259 | d = QJSValuePrivate::encode(qv4Value: *QJSValuePrivate::qv4ValuePtr(v: d)); |
260 | return; |
261 | case QJSValuePrivate::Kind::QStringPtr: |
262 | d = QJSValuePrivate::encode(stringValue: *QJSValuePrivate::qStringPtr(v: d)); |
263 | break; |
264 | } |
265 | } |
266 | |
267 | /*! |
268 | \fn QJSValue::QJSValue(QJSValue && other) |
269 | |
270 | Move constructor. Moves from \a other into this QJSValue object. |
271 | */ |
272 | |
273 | /*! |
274 | \fn QJSValue &QJSValue::operator=(QJSValue && other) |
275 | |
276 | Move-assigns \a other to this QJSValue object. |
277 | */ |
278 | |
279 | /*! |
280 | Destroys this QJSValue. |
281 | */ |
282 | QJSValue::~QJSValue() |
283 | { |
284 | QJSValuePrivate::free(jsval: this); |
285 | } |
286 | |
287 | /*! |
288 | Returns true if this QJSValue is of the primitive type Boolean; |
289 | otherwise returns false. |
290 | |
291 | \sa toBool() |
292 | */ |
293 | bool QJSValue::isBool() const |
294 | { |
295 | return QJSValuePrivate::tag(raw: d) == QJSValuePrivate::Kind::BoolValue; |
296 | } |
297 | |
298 | /*! |
299 | Returns true if this QJSValue is of the primitive type Number; |
300 | otherwise returns false. |
301 | |
302 | \sa toNumber() |
303 | */ |
304 | bool QJSValue::isNumber() const |
305 | { |
306 | switch (QJSValuePrivate::tag(raw: d)) { |
307 | case QJSValuePrivate::Kind::IntValue: |
308 | case QJSValuePrivate::Kind::DoublePtr: |
309 | return true; |
310 | default: |
311 | break; |
312 | } |
313 | |
314 | return false; |
315 | } |
316 | |
317 | /*! |
318 | Returns true if this QJSValue is of the primitive type Null; |
319 | otherwise returns false. |
320 | */ |
321 | bool QJSValue::isNull() const |
322 | { |
323 | return QJSValuePrivate::tag(raw: d) == QJSValuePrivate::Kind::Null; |
324 | } |
325 | |
326 | /*! |
327 | Returns true if this QJSValue is of the primitive type String; |
328 | otherwise returns false. |
329 | |
330 | \sa toString() |
331 | */ |
332 | bool QJSValue::isString() const |
333 | { |
334 | switch (QJSValuePrivate::tag(raw: d)) { |
335 | case QJSValuePrivate::Kind::QStringPtr: |
336 | return true; |
337 | case QJSValuePrivate::Kind::QV4ValuePtr: { |
338 | return QJSValuePrivate::qv4ValuePtr(v: d)->isString(); |
339 | } |
340 | default: |
341 | break; |
342 | } |
343 | |
344 | return false; |
345 | } |
346 | |
347 | /*! |
348 | Returns true if this QJSValue is of the primitive type Undefined or if the managed value |
349 | has been cleared (by deleting the engine). Otherwise returns false. |
350 | */ |
351 | bool QJSValue::isUndefined() const |
352 | { |
353 | switch (QJSValuePrivate::tag(raw: d)) { |
354 | case QJSValuePrivate::Kind::Undefined: |
355 | return true; |
356 | case QJSValuePrivate::Kind::QV4ValuePtr: |
357 | return QJSValuePrivate::qv4ValuePtr(v: d)->isUndefined(); |
358 | default: |
359 | break; |
360 | } |
361 | |
362 | return false; |
363 | } |
364 | |
365 | /*! |
366 | Returns true if this QJSValue is an object of the Error class; |
367 | otherwise returns false. |
368 | |
369 | \sa errorType(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions} |
370 | */ |
371 | bool QJSValue::isError() const |
372 | { |
373 | return QJSValuePrivate::asManagedType<ErrorObject>(jsval: this); |
374 | } |
375 | |
376 | /*! |
377 | Returns true if this QJSValue is an object of the URL JavaScript class; |
378 | otherwise returns false. |
379 | |
380 | \note For a QJSValue that contains a QUrl, this function returns false. |
381 | However, \c{toVariant().value<QUrl>()} works in both cases. |
382 | */ |
383 | bool QJSValue::isUrl() const |
384 | { |
385 | return QJSValuePrivate::asManagedType<UrlObject>(jsval: this); |
386 | } |
387 | |
388 | /*! |
389 | \since 5.12 |
390 | Returns the error type this QJSValue represents if it is an Error object. |
391 | Otherwise, returns \c NoError." |
392 | |
393 | \sa isError(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions} |
394 | */ |
395 | QJSValue::ErrorType QJSValue::errorType() const |
396 | { |
397 | const QV4::ErrorObject *error = QJSValuePrivate::asManagedType<ErrorObject>(jsval: this); |
398 | if (!error) |
399 | return NoError; |
400 | switch (error->d()->errorType) { |
401 | case QV4::Heap::ErrorObject::Error: |
402 | return GenericError; |
403 | case QV4::Heap::ErrorObject::EvalError: |
404 | return EvalError; |
405 | case QV4::Heap::ErrorObject::RangeError: |
406 | return RangeError; |
407 | case QV4::Heap::ErrorObject::ReferenceError: |
408 | return ReferenceError; |
409 | case QV4::Heap::ErrorObject::SyntaxError: |
410 | return SyntaxError; |
411 | case QV4::Heap::ErrorObject::TypeError: |
412 | return TypeError; |
413 | case QV4::Heap::ErrorObject::URIError: |
414 | return URIError; |
415 | } |
416 | Q_UNREACHABLE_RETURN(NoError); |
417 | } |
418 | |
419 | /*! |
420 | Returns true if this QJSValue is an object of the Array class; |
421 | otherwise returns false. |
422 | |
423 | \sa QJSEngine::newArray() |
424 | */ |
425 | bool QJSValue::isArray() const |
426 | { |
427 | return QJSValuePrivate::asManagedType<ArrayObject>(jsval: this); |
428 | } |
429 | |
430 | /*! |
431 | Returns true if this QJSValue is of the Object type; otherwise |
432 | returns false. |
433 | |
434 | Note that function values, variant values, and QObject values are |
435 | objects, so this function returns true for such values. |
436 | |
437 | \sa QJSEngine::newObject() |
438 | */ |
439 | bool QJSValue::isObject() const |
440 | { |
441 | return QJSValuePrivate::asManagedType<QV4::Object>(jsval: this); |
442 | } |
443 | |
444 | /*! |
445 | Returns true if this QJSValue is a function, otherwise |
446 | returns false. |
447 | |
448 | \sa call() |
449 | */ |
450 | bool QJSValue::isCallable() const |
451 | { |
452 | return QJSValuePrivate::asManagedType<FunctionObject>(jsval: this); |
453 | } |
454 | |
455 | #if QT_DEPRECATED_SINCE(6, 9) |
456 | /*! |
457 | \deprecated [6.9] |
458 | Returns true if this QJSValue is a variant value; |
459 | otherwise returns false. |
460 | |
461 | \warning This function is likely to give unexpected results. |
462 | A variant value is only constructed by the QJSEngine in a very |
463 | limited number of cases. This used to be different before Qt |
464 | 5.14, where \l{QJSEngine::toScriptValue} would have created |
465 | them for more types instead of corresponding ECMAScript types. |
466 | You can get a valid \l QVariant via \l toVariant for many values |
467 | for which \c{isVariant} returns false. |
468 | |
469 | \sa toVariant() |
470 | */ |
471 | bool QJSValue::isVariant() const |
472 | { |
473 | if (QJSValuePrivate::asManagedType<QV4::VariantObject>(jsval: this)) |
474 | return true; |
475 | if (auto vt = QJSValuePrivate::asManagedType<QV4::QQmlValueTypeWrapper>(jsval: this)) |
476 | if (vt->metaObject() == &QQmlVarForeign::staticMetaObject) |
477 | return true; |
478 | return false; |
479 | } |
480 | #endif |
481 | |
482 | /*! |
483 | Returns the string value of this QJSValue, as defined in |
484 | \l{ECMA-262} section 9.8, "ToString". |
485 | |
486 | Note that if this QJSValue is an object, calling this function |
487 | has side effects on the script engine, since the engine will call |
488 | the object's toString() function (and possibly valueOf()) in an |
489 | attempt to convert the object to a primitive value (possibly |
490 | resulting in an uncaught script exception). |
491 | |
492 | \sa isString() |
493 | */ |
494 | QString QJSValue::toString() const |
495 | { |
496 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) |
497 | return *string; |
498 | |
499 | return QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: this)).toQStringNoThrow(); |
500 | } |
501 | |
502 | template<typename T> |
503 | T caughtResult(const QJSValue *v, T (QV4::Value::*convert)() const) |
504 | { |
505 | const T result = (QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: v)).*convert)(); |
506 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: v); |
507 | if (engine && engine->hasException) { |
508 | engine->catchException(); |
509 | return T(); |
510 | } |
511 | return result; |
512 | } |
513 | |
514 | /*! |
515 | Returns the number value of this QJSValue, as defined in |
516 | \l{ECMA-262} section 9.3, "ToNumber". |
517 | |
518 | Note that if this QJSValue is an object, calling this function |
519 | has side effects on the script engine, since the engine will call |
520 | the object's valueOf() function (and possibly toString()) in an |
521 | attempt to convert the object to a primitive value (possibly |
522 | resulting in an uncaught script exception). |
523 | |
524 | \sa isNumber(), toInt(), toUInt() |
525 | */ |
526 | double QJSValue::toNumber() const |
527 | { |
528 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) |
529 | return RuntimeHelpers::stringToNumber(s: *string); |
530 | |
531 | return caughtResult<double>(v: this, convert: &QV4::Value::toNumber); |
532 | } |
533 | |
534 | /*! |
535 | Returns the boolean value of this QJSValue, using the conversion |
536 | rules described in \l{ECMA-262} section 9.2, "ToBoolean". |
537 | |
538 | Note that if this QJSValue is an object, calling this function |
539 | has side effects on the script engine, since the engine will call |
540 | the object's valueOf() function (and possibly toString()) in an |
541 | attempt to convert the object to a primitive value (possibly |
542 | resulting in an uncaught script exception). |
543 | |
544 | \sa isBool() |
545 | */ |
546 | bool QJSValue::toBool() const |
547 | { |
548 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) |
549 | return string->size() > 0; |
550 | |
551 | return caughtResult<bool>(v: this, convert: &QV4::Value::toBoolean); |
552 | } |
553 | |
554 | /*! |
555 | Returns the signed 32-bit integer value of this QJSValue, using |
556 | the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32". |
557 | |
558 | Note that if this QJSValue is an object, calling this function |
559 | has side effects on the script engine, since the engine will call |
560 | the object's valueOf() function (and possibly toString()) in an |
561 | attempt to convert the object to a primitive value (possibly |
562 | resulting in an uncaught script exception). |
563 | |
564 | \sa toNumber(), toUInt() |
565 | */ |
566 | qint32 QJSValue::toInt() const |
567 | { |
568 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) |
569 | return QV4::Value::toInt32(d: RuntimeHelpers::stringToNumber(s: *string)); |
570 | |
571 | return caughtResult<qint32>(v: this, convert: &QV4::Value::toInt32); |
572 | } |
573 | |
574 | /*! |
575 | Returns the unsigned 32-bit integer value of this QJSValue, using |
576 | the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32". |
577 | |
578 | Note that if this QJSValue is an object, calling this function |
579 | has side effects on the script engine, since the engine will call |
580 | the object's valueOf() function (and possibly toString()) in an |
581 | attempt to convert the object to a primitive value (possibly |
582 | resulting in an uncaught script exception). |
583 | |
584 | \sa toNumber(), toInt() |
585 | */ |
586 | quint32 QJSValue::toUInt() const |
587 | { |
588 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) |
589 | return QV4::Value::toUInt32(d: RuntimeHelpers::stringToNumber(s: *string)); |
590 | |
591 | return caughtResult<quint32>(v: this, convert: &QV4::Value::toUInt32); |
592 | } |
593 | |
594 | /*! |
595 | \overload |
596 | |
597 | Returns toVariant(ConvertJSObjects). |
598 | |
599 | \sa isVariant() |
600 | */ |
601 | QVariant QJSValue::toVariant() const |
602 | { |
603 | return toVariant(behavior: ConvertJSObjects); |
604 | } |
605 | |
606 | /*! |
607 | Returns the QVariant value of this QJSValue, if it can be |
608 | converted to a QVariant; otherwise returns an invalid QVariant. |
609 | Some JavaScript types and objects have native expressions in Qt. |
610 | Those are converted to their native expressions. For example: |
611 | |
612 | \table |
613 | \header \li Input Type \li Result |
614 | \row \li Undefined \li An invalid QVariant. |
615 | \row \li Null \li A QVariant containing a null pointer (QMetaType::Nullptr). |
616 | \row \li Boolean \li A QVariant containing the value of the boolean. |
617 | \row \li Number \li A QVariant containing the value of the number. |
618 | \row \li String \li A QVariant containing the value of the string. |
619 | \row \li QVariant Object \li The result is the QVariant value of the object (no conversion). |
620 | \row \li QObject Object \li A QVariant containing a pointer to the QObject. |
621 | \row \li Date Object \li A QVariant containing the date value (toDateTime()). |
622 | \row \li RegularExpression Object \li A QVariant containing the regular expression value. |
623 | \endtable |
624 | |
625 | For other types the \a behavior parameter is relevant. If |
626 | \c ConvertJSObjects is given, a best effort but possibly lossy conversion is |
627 | attempted. Generic JavaScript objects are converted to QVariantMap. |
628 | JavaScript arrays are converted to QVariantList. Each property or element is |
629 | converted to a QVariant, recursively; cyclic references are not followed. |
630 | JavaScript function objects are dropped. If \c RetainJSObjects is given, the |
631 | QJSValue is wrapped into a QVariant via QVariant::fromValue(). The resulting |
632 | conversion is lossless but the internal structure of the objects is not |
633 | immediately accessible. |
634 | |
635 | \sa isVariant() |
636 | */ |
637 | QVariant QJSValue::toVariant(QJSValue::ObjectConversionBehavior behavior) const |
638 | { |
639 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) |
640 | return QVariant(*string); |
641 | |
642 | QV4::Value val = QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: this)); |
643 | if (val.isUndefined()) |
644 | return QVariant(); |
645 | if (val.isNull()) |
646 | return QVariant(QMetaType::fromType<std::nullptr_t>(), nullptr); |
647 | if (val.isBoolean()) |
648 | return QVariant(val.booleanValue()); |
649 | if (val.isInt32()) // Includes doubles that can be losslessly casted to int |
650 | return QVariant(val.integerValue()); |
651 | if (val.isNumber()) |
652 | return QVariant(val.doubleValue()); |
653 | |
654 | Q_ASSERT(val.isManaged()); |
655 | |
656 | if (val.isString()) |
657 | return QVariant(val.toQString()); |
658 | if (val.as<QV4::Managed>()) { |
659 | if (behavior == RetainJSObjects) |
660 | return QV4::ExecutionEngine::toVariant( |
661 | value: val, /*typeHint*/ QMetaType{}, /*createJSValueForObjectsAndSymbols=*/ true); |
662 | else |
663 | return QV4::ExecutionEngine::toVariantLossy(value: val); |
664 | } |
665 | |
666 | Q_ASSERT(false); |
667 | return QVariant(); |
668 | } |
669 | |
670 | /*! |
671 | * Converts the value to a QJSPrimitiveValue. If the value holds a type |
672 | * supported by QJSPrimitiveValue, the value is copied. Otherwise the |
673 | * value is converted to a string, and the string is stored in |
674 | * QJSPrimitiveValue. |
675 | * |
676 | * \note Conversion of a managed value to a string can throw an exception. In |
677 | * particular, symbols cannot be coerced into strings, or a custom |
678 | * toString() method may throw. In this case the result is the undefined |
679 | * value and the engine carries an error after the conversion. |
680 | */ |
681 | QJSPrimitiveValue QJSValue::toPrimitive() const |
682 | { |
683 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) |
684 | return *string; |
685 | |
686 | const QV4::Value val = QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: this)); |
687 | return QV4::ExecutionEngine::createPrimitive(v: &val); |
688 | } |
689 | |
690 | /*! |
691 | Calls this QJSValue as a function, passing \a args as arguments |
692 | to the function, and using the globalObject() as the "this"-object. |
693 | Returns the value returned from the function. |
694 | |
695 | If this QJSValue is not callable, call() does nothing and |
696 | returns an undefined QJSValue. |
697 | |
698 | Calling call() can cause an exception to occur in the script engine; |
699 | in that case, call() returns the value that was thrown (typically an |
700 | \c{Error} object). You can call isError() on the return value to |
701 | determine whether an exception occurred. |
702 | |
703 | \sa isCallable(), callWithInstance(), callAsConstructor() |
704 | */ |
705 | QJSValue QJSValue::call(const QJSValueList &args) const |
706 | { |
707 | const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(jsval: this); |
708 | if (!f) |
709 | return QJSValue(); |
710 | |
711 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
712 | Q_ASSERT(engine); |
713 | |
714 | Scope scope(engine); |
715 | JSCallArguments jsCallData(scope, args.size()); |
716 | *jsCallData.thisObject = engine->globalObject; |
717 | for (int i = 0; i < args.size(); ++i) { |
718 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) { |
719 | qWarning(msg: "QJSValue::call() failed: cannot call function with argument created in a different engine"); |
720 | return QJSValue(); |
721 | } |
722 | jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: args.at(i)); |
723 | } |
724 | |
725 | ScopedValue result(scope, f->call(data: jsCallData)); |
726 | if (engine->hasException) |
727 | result = engine->catchException(); |
728 | if (engine->isInterrupted.loadRelaxed()) |
729 | result = engine->newErrorObject(QStringLiteral("Interrupted")); |
730 | |
731 | return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue()); |
732 | } |
733 | |
734 | /*! |
735 | Calls this QJSValue as a function, using \a instance as |
736 | the `this' object in the function call, and passing \a args |
737 | as arguments to the function. Returns the value returned from |
738 | the function. |
739 | |
740 | If this QJSValue is not a function, call() does nothing |
741 | and returns an undefined QJSValue. |
742 | |
743 | Note that if \a instance is not an object, the global object |
744 | (see \l{QJSEngine::globalObject()}) will be used as the |
745 | `this' object. |
746 | |
747 | Calling call() can cause an exception to occur in the script engine; |
748 | in that case, call() returns the value that was thrown (typically an |
749 | \c{Error} object). You can call isError() on the return value to |
750 | determine whether an exception occurred. |
751 | |
752 | \sa call() |
753 | */ |
754 | QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args) const |
755 | { |
756 | const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(jsval: this); |
757 | if (!f) |
758 | return QJSValue(); |
759 | |
760 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
761 | Q_ASSERT(engine); |
762 | Scope scope(engine); |
763 | |
764 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: instance)) { |
765 | qWarning(msg: "QJSValue::call() failed: cannot call function with thisObject created in a different engine"); |
766 | return QJSValue(); |
767 | } |
768 | |
769 | JSCallArguments jsCallData(scope, args.size()); |
770 | *jsCallData.thisObject = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: instance); |
771 | for (int i = 0; i < args.size(); ++i) { |
772 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) { |
773 | qWarning(msg: "QJSValue::call() failed: cannot call function with argument created in a different engine"); |
774 | return QJSValue(); |
775 | } |
776 | jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: args.at(i)); |
777 | } |
778 | |
779 | ScopedValue result(scope, f->call(data: jsCallData)); |
780 | if (engine->hasException) |
781 | result = engine->catchException(); |
782 | if (engine->isInterrupted.loadRelaxed()) |
783 | result = engine->newErrorObject(QStringLiteral("Interrupted")); |
784 | |
785 | return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue()); |
786 | } |
787 | |
788 | /*! |
789 | Creates a new \c{Object} and calls this QJSValue as a |
790 | constructor, using the created object as the `this' object and |
791 | passing \a args as arguments. If the return value from the |
792 | constructor call is an object, then that object is returned; |
793 | otherwise the default constructed object is returned. |
794 | |
795 | If this QJSValue is not a function, callAsConstructor() does |
796 | nothing and returns an undefined QJSValue. |
797 | |
798 | Calling this function can cause an exception to occur in the |
799 | script engine; in that case, the value that was thrown |
800 | (typically an \c{Error} object) is returned. You can call |
801 | isError() on the return value to determine whether an |
802 | exception occurred. |
803 | |
804 | \sa call(), QJSEngine::newObject() |
805 | */ |
806 | QJSValue QJSValue::callAsConstructor(const QJSValueList &args) const |
807 | { |
808 | const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(jsval: this); |
809 | if (!f) |
810 | return QJSValue(); |
811 | |
812 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
813 | Q_ASSERT(engine); |
814 | |
815 | Scope scope(engine); |
816 | JSCallArguments jsCallData(scope, args.size()); |
817 | for (int i = 0; i < args.size(); ++i) { |
818 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) { |
819 | qWarning(msg: "QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine"); |
820 | return QJSValue(); |
821 | } |
822 | jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: args.at(i)); |
823 | } |
824 | |
825 | ScopedValue result(scope, f->callAsConstructor(data: jsCallData)); |
826 | if (engine->hasException) |
827 | result = engine->catchException(); |
828 | if (engine->isInterrupted.loadRelaxed()) |
829 | result = engine->newErrorObject(QStringLiteral("Interrupted")); |
830 | |
831 | return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue()); |
832 | } |
833 | |
834 | /*! |
835 | If this QJSValue is an object, returns the internal prototype |
836 | (\c{__proto__} property) of this object; otherwise returns an |
837 | undefined QJSValue. |
838 | |
839 | \sa setPrototype(), isObject() |
840 | */ |
841 | QJSValue QJSValue::prototype() const |
842 | { |
843 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
844 | if (!engine) |
845 | return QJSValue(); |
846 | QV4::Scope scope(engine); |
847 | ScopedObject o(scope, QJSValuePrivate::asManagedType<QV4::Object>(jsval: this)); |
848 | if (!o) |
849 | return QJSValue(); |
850 | ScopedObject p(scope, o->getPrototypeOf()); |
851 | if (!p) |
852 | return QJSValue(NullValue); |
853 | return QJSValuePrivate::fromReturnedValue(d: p.asReturnedValue()); |
854 | } |
855 | |
856 | /*! |
857 | If this QJSValue is an object, sets the internal prototype |
858 | (\c{__proto__} property) of this object to be \a prototype; |
859 | if the QJSValue is null, it sets the prototype to null; |
860 | otherwise does nothing. |
861 | |
862 | The internal prototype should not be confused with the public |
863 | property with name "prototype"; the public prototype is usually |
864 | only set on functions that act as constructors. |
865 | |
866 | \sa prototype(), isObject() |
867 | */ |
868 | void QJSValue::setPrototype(const QJSValue& prototype) |
869 | { |
870 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
871 | if (!engine) |
872 | return; |
873 | Scope scope(engine); |
874 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
875 | if (!o) |
876 | return; |
877 | QV4::Value val = QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: &prototype)); |
878 | if (val.isNull()) { |
879 | o->setPrototypeOf(nullptr); |
880 | return; |
881 | } |
882 | |
883 | ScopedObject p(scope, val); |
884 | if (!p) |
885 | return; |
886 | if (o->engine() != p->engine()) { |
887 | qWarning(msg: "QJSValue::setPrototype() failed: cannot set a prototype created in a different engine"); |
888 | return; |
889 | } |
890 | if (!o->setPrototypeOf(p)) |
891 | qWarning(msg: "QJSValue::setPrototype() failed: cyclic prototype value"); |
892 | } |
893 | |
894 | /*! |
895 | Assigns the \a other value to this QJSValue. |
896 | |
897 | Note that if \a other is an object (isObject() returns true), |
898 | only a reference to the underlying object will be assigned; |
899 | the object itself will not be copied. |
900 | */ |
901 | QJSValue& QJSValue::operator=(const QJSValue& other) |
902 | { |
903 | if (d == other.d) |
904 | return *this; |
905 | |
906 | QJSValuePrivate::free(jsval: this); |
907 | d = 0; |
908 | |
909 | if (const QString *string = QJSValuePrivate::asQString(jsval: &other)) |
910 | QJSValuePrivate::setString(jsval: this, s: *string); |
911 | else |
912 | QJSValuePrivate::setValue(jsval: this, v: QJSValuePrivate::asReturnedValue(jsval: &other)); |
913 | |
914 | return *this; |
915 | } |
916 | |
917 | QJSValue::QJSValue(QJSPrimitiveValue &&value) |
918 | { |
919 | switch (value.type()) { |
920 | case QJSPrimitiveValue::Undefined: |
921 | d = QJSValuePrivate::encodeUndefined(); |
922 | return; |
923 | case QJSPrimitiveValue::Null: |
924 | d = QJSValuePrivate::encodeNull(); |
925 | return; |
926 | case QJSPrimitiveValue::Boolean: |
927 | d = QJSValuePrivate::encode(boolValue: value.asBoolean()); |
928 | return; |
929 | case QJSPrimitiveValue::Integer: |
930 | d = QJSValuePrivate::encode(intValue: value.asInteger()); |
931 | return; |
932 | case QJSPrimitiveValue::Double: |
933 | d = QJSValuePrivate::encode(doubleValue: value.asDouble()); |
934 | return; |
935 | case QJSPrimitiveValue::String: |
936 | d = QJSValuePrivate::encode(stringValue: value.asString()); |
937 | return; |
938 | } |
939 | |
940 | Q_UNREACHABLE(); |
941 | } |
942 | |
943 | QJSValue::QJSValue(QJSManagedValue &&value) |
944 | { |
945 | if (!value.d) { |
946 | d = QV4::Encode::undefined(); |
947 | } else if (value.d->isManaged()) { |
948 | // If it's managed, we can adopt the persistent value. |
949 | QJSValuePrivate::adoptPersistentValue(jsval: this, v: value.d); |
950 | value.d = nullptr; |
951 | } else { |
952 | d = QJSValuePrivate::encode(qv4Value: *value.d); |
953 | QV4::PersistentValueStorage::free(v: value.d); |
954 | value.d = nullptr; |
955 | } |
956 | } |
957 | |
958 | static bool js_equal(const QString &string, const QV4::Value &value) |
959 | { |
960 | if (String *s = value.stringValue()) |
961 | return string == s->toQString(); |
962 | if (value.isNumber()) |
963 | return RuntimeHelpers::stringToNumber(s: string) == value.asDouble(); |
964 | if (value.isBoolean()) |
965 | return RuntimeHelpers::stringToNumber(s: string) == double(value.booleanValue()); |
966 | if (QV4::Object *o = value.objectValue()) { |
967 | Scope scope(o->engine()); |
968 | ScopedValue p(scope, RuntimeHelpers::toPrimitive(value, typeHint: PREFERREDTYPE_HINT)); |
969 | return js_equal(string, value: p); |
970 | } |
971 | return false; |
972 | } |
973 | |
974 | /*! |
975 | Returns true if this QJSValue is equal to \a other, otherwise |
976 | returns false. The comparison follows the behavior described in |
977 | \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison |
978 | Algorithm". |
979 | |
980 | This function can return true even if the type of this QJSValue |
981 | is different from the type of the \a other value; i.e. the |
982 | comparison is not strict. For example, comparing the number 9 to |
983 | the string "9" returns true; comparing an undefined value to a null |
984 | value returns true; comparing a \c{Number} object whose primitive |
985 | value is 6 to a \c{String} object whose primitive value is "6" |
986 | returns true; and comparing the number 1 to the boolean value |
987 | \c{true} returns true. If you want to perform a comparison |
988 | without such implicit value conversion, use strictlyEquals(). |
989 | |
990 | Note that if this QJSValue or the \a other value are objects, |
991 | calling this function has side effects on the script engine, since |
992 | the engine will call the object's valueOf() function (and possibly |
993 | toString()) in an attempt to convert the object to a primitive value |
994 | (possibly resulting in an uncaught script exception). |
995 | |
996 | \sa strictlyEquals() |
997 | */ |
998 | bool QJSValue::equals(const QJSValue& other) const |
999 | { |
1000 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) { |
1001 | if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other)) |
1002 | return *string == *otherString; |
1003 | return js_equal(string: *string, value: QJSValuePrivate::asReturnedValue(jsval: &other)); |
1004 | } |
1005 | |
1006 | if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other)) |
1007 | return js_equal(string: *otherString, value: QJSValuePrivate::asReturnedValue(jsval: this)); |
1008 | |
1009 | return Runtime::CompareEqual::call(QJSValuePrivate::asReturnedValue(jsval: this), |
1010 | QJSValuePrivate::asReturnedValue(jsval: &other)); |
1011 | } |
1012 | |
1013 | /*! |
1014 | Returns true if this QJSValue is equal to \a other using strict |
1015 | comparison (no conversion), otherwise returns false. The comparison |
1016 | follows the behavior described in \l{ECMA-262} section 11.9.6, "The |
1017 | Strict Equality Comparison Algorithm". |
1018 | |
1019 | If the type of this QJSValue is different from the type of the |
1020 | \a other value, this function returns false. If the types are equal, |
1021 | the result depends on the type, as shown in the following table: |
1022 | |
1023 | \table |
1024 | \header \li Type \li Result |
1025 | \row \li Undefined \li true |
1026 | \row \li Null \li true |
1027 | \row \li Boolean \li true if both values are true, false otherwise |
1028 | \row \li Number \li false if either value is NaN (Not-a-Number); true if values are equal, false otherwise |
1029 | \row \li String \li true if both values are exactly the same sequence of characters, false otherwise |
1030 | \row \li Object \li true if both values refer to the same object, false otherwise |
1031 | \endtable |
1032 | |
1033 | \sa equals() |
1034 | */ |
1035 | bool QJSValue::strictlyEquals(const QJSValue& other) const |
1036 | { |
1037 | if (const QString *string = QJSValuePrivate::asQString(jsval: this)) { |
1038 | if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other)) |
1039 | return *string == *otherString; |
1040 | if (const String *s = QJSValuePrivate::asManagedType<String>(jsval: &other)) |
1041 | return *string == s->toQString(); |
1042 | return false; |
1043 | } |
1044 | |
1045 | if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other)) { |
1046 | if (const String *s = QJSValuePrivate::asManagedType<String>(jsval: this)) |
1047 | return *otherString == s->toQString(); |
1048 | return false; |
1049 | } |
1050 | |
1051 | return RuntimeHelpers::strictEqual(x: QJSValuePrivate::asReturnedValue(jsval: this), |
1052 | y: QJSValuePrivate::asReturnedValue(jsval: &other)); |
1053 | } |
1054 | |
1055 | /*! |
1056 | Returns the value of this QJSValue's property with the given \a name. |
1057 | If no such property exists, an undefined QJSValue is returned. |
1058 | |
1059 | If the property is implemented using a getter function (i.e. has the |
1060 | PropertyGetter flag set), calling property() has side-effects on the |
1061 | script engine, since the getter function will be called (possibly |
1062 | resulting in an uncaught script exception). If an exception |
1063 | occurred, property() returns the value that was thrown (typically |
1064 | an \c{Error} object). |
1065 | |
1066 | To access array elements, use the |
1067 | \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)} |
1068 | overload instead. |
1069 | |
1070 | \sa setProperty(), hasProperty(), QJSValueIterator |
1071 | */ |
1072 | QJSValue QJSValue::property(const QString& name) const |
1073 | { |
1074 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1075 | if (!engine) |
1076 | return QJSValue(); |
1077 | |
1078 | QV4::Scope scope(engine); |
1079 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1080 | if (!o) |
1081 | return QJSValue(); |
1082 | |
1083 | ScopedString s(scope, engine->newString(s: name)); |
1084 | QV4::ScopedValue result(scope, o->get(id: s->toPropertyKey())); |
1085 | if (engine->hasException) |
1086 | result = engine->catchException(); |
1087 | |
1088 | return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue()); |
1089 | } |
1090 | |
1091 | /*! |
1092 | \overload |
1093 | |
1094 | Returns the property at the given \a arrayIndex. |
1095 | |
1096 | It is possible to access elements in an array in two ways. The first is to |
1097 | use the array index as the property name: |
1098 | |
1099 | \code |
1100 | qDebug() << jsValueArray.property(QLatin1String("4")).toString(); |
1101 | \endcode |
1102 | |
1103 | The second is to use the overload that takes an index: |
1104 | |
1105 | \code |
1106 | qDebug() << jsValueArray.property(4).toString(); |
1107 | \endcode |
1108 | |
1109 | Both of these approaches achieve the same result, except that the latter: |
1110 | |
1111 | \list |
1112 | \li Is easier to use (can use an integer directly) |
1113 | \li Is faster (no conversion to integer) |
1114 | \endlist |
1115 | |
1116 | If this QJSValue is not an Array object, this function behaves |
1117 | as if property() was called with the string representation of \a |
1118 | arrayIndex. |
1119 | */ |
1120 | QJSValue QJSValue::property(quint32 arrayIndex) const |
1121 | { |
1122 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1123 | if (!engine) |
1124 | return QJSValue(); |
1125 | |
1126 | QV4::Scope scope(engine); |
1127 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1128 | if (!o) |
1129 | return QJSValue(); |
1130 | |
1131 | QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(name: engine->id_uintMax()) : o->get(idx: arrayIndex)); |
1132 | if (engine->hasException) |
1133 | engine->catchException(); |
1134 | return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue()); |
1135 | } |
1136 | |
1137 | /*! |
1138 | Sets the value of this QJSValue's property with the given \a name to |
1139 | the given \a value. |
1140 | |
1141 | If this QJSValue is not an object, this function does nothing. |
1142 | |
1143 | If this QJSValue does not already have a property with name \a name, |
1144 | a new property is created. |
1145 | |
1146 | To modify array elements, use the |
1147 | \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)} |
1148 | overload instead. |
1149 | |
1150 | \sa property(), deleteProperty() |
1151 | */ |
1152 | void QJSValue::setProperty(const QString& name, const QJSValue& value) |
1153 | { |
1154 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1155 | if (!engine) |
1156 | return; |
1157 | Scope scope(engine); |
1158 | |
1159 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1160 | if (!o) |
1161 | return; |
1162 | |
1163 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: value)) { |
1164 | qWarning(msg: "QJSValue::setProperty(%s) failed: cannot set value created in a different engine", name.toUtf8().constData()); |
1165 | return; |
1166 | } |
1167 | |
1168 | ScopedString s(scope, engine->newString(s: name)); |
1169 | QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(e: engine, jsval: value)); |
1170 | o->put(id: s->toPropertyKey(), v); |
1171 | if (engine->hasException) |
1172 | engine->catchException(); |
1173 | } |
1174 | |
1175 | /*! |
1176 | \overload |
1177 | |
1178 | Sets the property at the given \a arrayIndex to the given \a value. |
1179 | |
1180 | It is possible to modify elements in an array in two ways. The first is to |
1181 | use the array index as the property name: |
1182 | |
1183 | \code |
1184 | jsValueArray.setProperty(QLatin1String("4"), value); |
1185 | \endcode |
1186 | |
1187 | The second is to use the overload that takes an index: |
1188 | |
1189 | \code |
1190 | jsValueArray.setProperty(4, value); |
1191 | \endcode |
1192 | |
1193 | Both of these approaches achieve the same result, except that the latter: |
1194 | |
1195 | \list |
1196 | \li Is easier to use (can use an integer directly) |
1197 | \li Is faster (no conversion to integer) |
1198 | \endlist |
1199 | |
1200 | If this QJSValue is not an Array object, this function behaves |
1201 | as if setProperty() was called with the string representation of \a |
1202 | arrayIndex. |
1203 | |
1204 | \sa {QJSValue::}{property(quint32 arrayIndex)}, {Working With Arrays} |
1205 | */ |
1206 | void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) |
1207 | { |
1208 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1209 | if (!engine) |
1210 | return; |
1211 | Scope scope(engine); |
1212 | |
1213 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1214 | if (!o) |
1215 | return; |
1216 | |
1217 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: value)) { |
1218 | qWarning(msg: "QJSValue::setProperty(%d) failed: cannot set value created in a different engine", arrayIndex); |
1219 | return; |
1220 | } |
1221 | |
1222 | QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(e: engine, jsval: value)); |
1223 | PropertyKey id = arrayIndex != UINT_MAX ? PropertyKey::fromArrayIndex(idx: arrayIndex) : engine->id_uintMax()->propertyKey(); |
1224 | o->put(id, v); |
1225 | if (engine->hasException) |
1226 | engine->catchException(); |
1227 | } |
1228 | |
1229 | /*! |
1230 | Attempts to delete this object's property of the given \a name. |
1231 | Returns true if the property was deleted, otherwise returns false. |
1232 | |
1233 | The behavior of this function is consistent with the JavaScript |
1234 | delete operator. In particular: |
1235 | |
1236 | \list |
1237 | \li Non-configurable properties cannot be deleted. |
1238 | \li This function will return true even if this object doesn't |
1239 | have a property of the given \a name (i.e., non-existent |
1240 | properties are "trivially deletable"). |
1241 | \li If this object doesn't have an own property of the given |
1242 | \a name, but an object in the prototype() chain does, the |
1243 | prototype object's property is not deleted, and this function |
1244 | returns true. |
1245 | \endlist |
1246 | |
1247 | \sa setProperty(), hasOwnProperty() |
1248 | */ |
1249 | bool QJSValue::deleteProperty(const QString &name) |
1250 | { |
1251 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1252 | if (!engine) |
1253 | return false; |
1254 | |
1255 | Scope scope(engine); |
1256 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1257 | if (!o) |
1258 | return false; |
1259 | |
1260 | ScopedString s(scope, engine->newString(s: name)); |
1261 | return o->deleteProperty(id: s->toPropertyKey()); |
1262 | } |
1263 | |
1264 | /*! |
1265 | Returns true if this object has a property of the given \a name, |
1266 | otherwise returns false. |
1267 | |
1268 | \sa property(), hasOwnProperty() |
1269 | */ |
1270 | bool QJSValue::hasProperty(const QString &name) const |
1271 | { |
1272 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1273 | if (!engine) |
1274 | return false; |
1275 | |
1276 | Scope scope(engine); |
1277 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1278 | if (!o) |
1279 | return false; |
1280 | |
1281 | ScopedString s(scope, engine->newString(s: name)); |
1282 | return o->hasProperty(id: s->toPropertyKey()); |
1283 | } |
1284 | |
1285 | /*! |
1286 | Returns true if this object has an own (not prototype-inherited) |
1287 | property of the given \a name, otherwise returns false. |
1288 | |
1289 | \sa property(), hasProperty() |
1290 | */ |
1291 | bool QJSValue::hasOwnProperty(const QString &name) const |
1292 | { |
1293 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1294 | if (!engine) |
1295 | return false; |
1296 | |
1297 | Scope scope(engine); |
1298 | ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1299 | if (!o) |
1300 | return false; |
1301 | |
1302 | ScopedString s(scope, engine->newIdentifier(text: name)); |
1303 | return o->getOwnProperty(id: s->propertyKey()) != Attr_Invalid; |
1304 | } |
1305 | |
1306 | /*! |
1307 | * If this QJSValue is a QObject, returns the QObject pointer |
1308 | * that the QJSValue represents; otherwise, returns \nullptr. |
1309 | * |
1310 | * If the QObject that this QJSValue wraps has been deleted, |
1311 | * this function returns \nullptr (i.e. it is possible for toQObject() |
1312 | * to return \nullptr even when isQObject() returns true). |
1313 | * |
1314 | * \sa isQObject() |
1315 | */ |
1316 | QObject *QJSValue::toQObject() const |
1317 | { |
1318 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1319 | if (!engine) |
1320 | return nullptr; |
1321 | QV4::Scope scope(engine); |
1322 | QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1323 | if (!wrapper) |
1324 | return nullptr; |
1325 | |
1326 | return wrapper->object(); |
1327 | } |
1328 | |
1329 | /*! |
1330 | \since 5.8 |
1331 | |
1332 | * If this QJSValue is a QMetaObject, returns the QMetaObject pointer |
1333 | * that the QJSValue represents; otherwise, returns \nullptr. |
1334 | * |
1335 | * \sa isQMetaObject() |
1336 | */ |
1337 | const QMetaObject *QJSValue::toQMetaObject() const |
1338 | { |
1339 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1340 | if (!engine) |
1341 | return nullptr; |
1342 | QV4::Scope scope(engine); |
1343 | QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(jsval: this)); |
1344 | if (!wrapper) |
1345 | return nullptr; |
1346 | |
1347 | return wrapper->metaObject(); |
1348 | } |
1349 | |
1350 | |
1351 | /*! |
1352 | Returns a QDateTime representation of this value, in local time. |
1353 | If this QJSValue is not a date, or the value of the date is NaN |
1354 | (Not-a-Number), an invalid QDateTime is returned. |
1355 | |
1356 | \sa isDate() |
1357 | */ |
1358 | QDateTime QJSValue::toDateTime() const |
1359 | { |
1360 | if (const QV4::DateObject *date = QJSValuePrivate::asManagedType<DateObject>(jsval: this)) |
1361 | return date->toQDateTime(); |
1362 | return QDateTime(); |
1363 | } |
1364 | |
1365 | /*! |
1366 | Returns true if this QJSValue is an object of the Date class; |
1367 | otherwise returns false. |
1368 | */ |
1369 | bool QJSValue::isDate() const |
1370 | { |
1371 | return QJSValuePrivate::asManagedType<DateObject>(jsval: this); |
1372 | } |
1373 | |
1374 | /*! |
1375 | Returns true if this QJSValue is an object of the RegExp class; |
1376 | otherwise returns false. |
1377 | */ |
1378 | bool QJSValue::isRegExp() const |
1379 | { |
1380 | return QJSValuePrivate::asManagedType<RegExpObject>(jsval: this); |
1381 | } |
1382 | |
1383 | /*! |
1384 | Returns true if this QJSValue is a QObject; otherwise returns |
1385 | false. |
1386 | |
1387 | Note: This function returns true even if the QObject that this |
1388 | QJSValue wraps has been deleted. |
1389 | |
1390 | \sa toQObject(), QJSEngine::newQObject() |
1391 | */ |
1392 | bool QJSValue::isQObject() const |
1393 | { |
1394 | return QJSValuePrivate::asManagedType<QV4::QObjectWrapper>(jsval: this); |
1395 | } |
1396 | |
1397 | /*! |
1398 | \since 5.8 |
1399 | |
1400 | Returns true if this QJSValue is a QMetaObject; otherwise returns |
1401 | false. |
1402 | |
1403 | \sa toQMetaObject(), QJSEngine::newQMetaObject() |
1404 | */ |
1405 | bool QJSValue::isQMetaObject() const |
1406 | { |
1407 | return QJSValuePrivate::asManagedType<QV4::QMetaObjectWrapper>(jsval: this); |
1408 | } |
1409 | |
1410 | #ifndef QT_NO_DATASTREAM |
1411 | QDataStream &operator<<(QDataStream &stream, const QJSValue &jsv) |
1412 | { |
1413 | quint32 isNullOrUndefined = 0; |
1414 | if (jsv.isNull()) |
1415 | isNullOrUndefined |= 0x1; |
1416 | if (jsv.isUndefined()) |
1417 | isNullOrUndefined |= 0x2; |
1418 | stream << isNullOrUndefined; |
1419 | if (!isNullOrUndefined) { |
1420 | const QVariant v = jsv.toVariant(); |
1421 | switch (v.userType()) { |
1422 | case QMetaType::Bool: |
1423 | case QMetaType::Double: |
1424 | case QMetaType::Int: |
1425 | case QMetaType::QString: |
1426 | v.save(ds&: stream); |
1427 | break; |
1428 | default: |
1429 | qWarning() << "QDataStream::operator<< was to save a non-trivial QJSValue." |
1430 | << "This is not supported anymore, please stream a QVariant instead."; |
1431 | QVariant().save(ds&: stream); |
1432 | break; |
1433 | } |
1434 | |
1435 | } |
1436 | return stream; |
1437 | } |
1438 | |
1439 | QDataStream &operator>>(QDataStream &stream, QJSValue &jsv) |
1440 | { |
1441 | quint32 isNullOrUndefined; |
1442 | stream >> isNullOrUndefined; |
1443 | |
1444 | if (isNullOrUndefined & 0x1) { |
1445 | jsv = QJSValue(QJSValue::NullValue); |
1446 | } else if (isNullOrUndefined & 0x2) { |
1447 | jsv = QJSValue(); |
1448 | } else { |
1449 | QVariant v; |
1450 | v.load(ds&: stream); |
1451 | |
1452 | switch (v.userType()) { |
1453 | case QMetaType::Bool: |
1454 | jsv = QJSValue(v.toBool()); |
1455 | break; |
1456 | case QMetaType::Double: |
1457 | jsv = QJSValue(v.toDouble()); |
1458 | break; |
1459 | case QMetaType::Int: |
1460 | jsv = QJSValue(v.toInt()); |
1461 | break; |
1462 | case QMetaType::QString: |
1463 | jsv = QJSValue(v.toString()); |
1464 | break; |
1465 | default: |
1466 | qWarning() << "QDataStream::operator>> to restore a non-trivial QJSValue." |
1467 | << "This is not supported anymore, please stream a QVariant instead."; |
1468 | break; |
1469 | } |
1470 | } |
1471 | return stream; |
1472 | } |
1473 | #endif |
1474 | |
1475 | QT_END_NAMESPACE |
1476 |
Definitions
- QJSValue
- QJSValue
- QJSValue
- QJSValue
- QJSValue
- QJSValue
- QJSValue
- QJSValue
- QJSValue
- ~QJSValue
- isBool
- isNumber
- isNull
- isString
- isUndefined
- isError
- isUrl
- errorType
- isArray
- isObject
- isCallable
- isVariant
- toString
- caughtResult
- toNumber
- toBool
- toInt
- toUInt
- toVariant
- toVariant
- toPrimitive
- call
- callWithInstance
- callAsConstructor
- prototype
- setPrototype
- operator=
- QJSValue
- QJSValue
- js_equal
- equals
- strictlyEquals
- property
- property
- setProperty
- setProperty
- deleteProperty
- hasProperty
- hasOwnProperty
- toQObject
- toQMetaObject
- toDateTime
- isDate
- isRegExp
- isQObject
- isQMetaObject
- operator<<
Learn to use CMake with our Intro Training
Find out more