QJSEngine does not support JavaScript lambdas as expected
-
Hi !
I'm getting a bit worried at the way QJSEngine handles lambdas using the new
() => {}
syntax.In some cases which are pretty rare and not completely consistent, the value of
this
from within one of this lambda will evaluate toundefined
. This happens when passing said lambda to C++ using QJSValue.Imagine the following QObject:
// header class MyObject : public QObject { Q_OBJECT public: MyObject(QObject* parent = nullptr) : QObject(parent) {} Q_INVOKABLE void pushTask(QJSValue value) { taskList << value; } Q_INVOKABLE void runTasks(); QList<QJSValue> taskList; }; // source void MyObject::runTasks() { for (QJSValue task : taskList) task.call(); }
Then if we interact with this QObject from JavaScript:
export class MyObject { doStuffOn(qobject) { qobject.pushTask(() => { console.log("Doing stuff from", this); }); qobject.runTasks(); } }
While you'd expect the output to be something such as:
Doing stuff from [object Object]
You may actually end up with:
Doing stuff from undefined
The example is simplified: in truth, you will never have this issue if
runTasks
is called right afterpushTask
. However, it will happen SOMETIMES ifrunTasks
only gets called from another context. Say, if you would add aQTimer
to this example, and triggerrunTasks
periodically rather than directly from JavaScript, you'd have a good chance to run in this issue.Up until now, I've been fixing the issue by using this form in JavaScript:
export class MyObject { doStuffOn(qobject) { const self = this; qobject.pushTask(() => { console.log("Doing stuff from", self); }); qobject.runTasks(); } }
Using a temporary variable to store
this
works. But I'm not completely satisfied with that solution.Any idea what's up with that ?