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
thisfrom 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 undefinedThe example is simplified: in truth, you will never have this issue if
runTasksis called right afterpushTask. However, it will happen SOMETIMES ifrunTasksonly gets called from another context. Say, if you would add aQTimerto this example, and triggerrunTasksperiodically 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
thisworks. But I'm not completely satisfied with that solution.Any idea what's up with that ?