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

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