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