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

source code of qtdeclarative/src/qml/jsapi/qjsvalue.cpp