QJSValue::equals returns false for QJSValue objects
-
Hi
should not QJSValue ::equals return true instead of false ?QJSEngine engine; QJSValue function = engine.evaluate("(function(){ return {age: 45} })"); QJSValue object1 = function.call(); QJSValue object2 = function.call(); qDebug() << object1.equals(object2); // returns false
-
I am not an expert but why would you expect it to return true? You are returning a JS object. Presumably you are expecting that to go through the object and compare each key/field in turn to do this? Do you have any evidence that it is supposed to do so? The docs state:
Returns true if this QJSValue is equal to other, otherwise returns false. The comparison follows the behavior described in ECMA-262 section 11.9.3, "The Abstract Equality Comparison Algorithm".
So have you looked at that (I have not)?
UPDATE
I couldn't resist it! https://262.ecma-international.org/5.1/#sec-11.9.3 I think you fall under:f. Return true if x and y refer to the same object. Otherwise, return false.
You do not satisfy this since you have created two objects separately. I would expect
object1 == object1
to be true butobject1 == object2
to be false. Which is what I thought would be the case. -
This is exactly how I interpret the equals function, that each property is compared.
Because if QJSValue is not an object but a primitive value, it works this way:
QJSEngine engine; QJSValue function = engine.evaluate("(function(){ return 3 })"); QJSValue primitive1 = function.call(); QJSValue primitive2 = engine.toScriptValue(3); qDebug() << primitive1.equals(primitive2); // returns true
-
@beecksche said in QJSValue::equals returns false for QJSValue objects:
This is exactly how I interpret the equals function, that each property is compared.
Then (according to me) you are wildly overoptimistic! I asked for a link where it says it would this? I gave you the link which I think makes it clear it does not. And which states how primitives are handled differently, versus objects. Did you read it? I believe you must write something other than
equals()
if you want to do that. It's not hard to search, how about the explanations/solutions in 5 Different Ways to Deep Compare JavaScript Objects? Which btw opens with:JavaScript has 7 primitive data types. We can compare the values of any of these types using an equality operator. However, comparing non-primitive types such as objects is tricky since the usual equality operators do not compare object values as one might expect.
-
To be honest, I skipped your link and, in my naivety, just assumed that it should be the same for objects.
Fortunately, js objects can be converted to a QVariantMap, which then be compared.
QJSEngine engine; QJSValue function = engine.evaluate("(function(){ return {age: 45} })"); QJSValue object1 = function.call(); QJSValue object2 = function.call(); qDebug() << object1.toVariant().toMap() == object2.toVariant().toMap(); // returns true
Thanks for the explanations!
-
@beecksche said in QJSValue::equals returns false for QJSValue objects:
To be honest, I skipped your link
:)
-
B beecksche has marked this topic as solved on
-
Hi @beecksche, as @JonB rightly points out, this appears to be doing the right thing according to the ECMAScript standard - you're asking the engine itself to perform an ECMAScript equality check.
Qt's
QJsonValue::operator==()
does compare the values recursively, so, depending on your needs, you can probably just convert theQJSValue
s toQJsonValue
s, and compare those; something like:QJSValue object1 = function.call(); QJSValue object2 = function.call(); const QJsonValue value1 = engine.fromScriptValue<QJsonValue>(object1); const QJsonValue value2 = engine.fromScriptValue<QJsonValue>(object2); qDebug() << (value1 == value2);
Cheers.