JavaScript 宿主环境

QML引擎提供的JavaScript宿主环境描述

QML 提供了一个专门用于编写 QML 应用程序的 JavaScript 宿主环境。这个环境与浏览器或服务器端 JavaScript 环境(如 Node.js)提供的宿主环境不同。例如,QML 不提供浏览器环境中常见的 window 对象或 DOM API

通用基础

与浏览器或服务器端JavaScript环境类似,QML运行时实现了ECMAScript语言规范标准。这提供了对标准定义的所有内置类型和函数的访问,例如Object、Array和Math。QML运行时实现了该标准的第7版。

Nullish Coalescing (??) (自 Qt 5.15 起) 和 Optional Chaining (?.) (自 Qt 6.2 起) 也在 QML 运行时中实现。

QML文档中没有明确记录标准的ECMAScript内置函数。有关它们使用的更多信息,请参考ECMA-262第7版标准或许多在线JavaScript参考和教程网站之一,例如W3Schools JavaScript参考(JavaScript对象参考部分)。许多网站专注于浏览器中的JavaScript,因此在某些情况下,您可能需要仔细检查规范以确定给定函数或对象是标准ECMAScript的一部分还是特定于浏览器环境。在上述W3Schools链接的情况下,JavaScript Objects Reference部分通常涵盖标准,而Browser Objects ReferenceHTML DOM Objects Reference部分是特定于浏览器的(因此不适用于QML)。

类型注解和断言

在QML文档中的函数声明可以并且应该包含类型注释。类型注释附加在参数的声明和函数本身上,用于注释返回类型。以下函数接受一个int和一个string参数,并返回一个QtObject

类型注释帮助像Qt Creator和qmllint这样的工具理解代码并提供更好的诊断。此外,它们使得从C++中使用函数更加容易。更多信息请参见从C++与QML对象交互

类型断言(有时称为as-casts)也可以用于将对象转换为不同的对象类型。如果对象实际上是给定类型,则类型断言返回相同的对象。如果不是,则返回null。在以下代码片段中,我们在访问特定成员之前断言parent对象是Rectangle

可选链(?.)可以避免在父元素实际上不是一个矩形时抛出异常。在这种情况下,选择“red”作为parentColor

自 Qt 6.7 起,调用函数时始终强制执行类型注释。值会根据需要强制转换为所需的类型。以前,类型注释被解释器和 JIT 编译器忽略,但在编译为 C++ 时由 qmlcachegenqmlsc 强制执行。这可能导致在某些边缘情况下行为上的差异。为了明确请求解释器和 JIT 的旧行为,您可以在 QML 文档中添加以下内容:

QML 全局对象

QML JavaScript 宿主环境实现了许多宿主对象和函数,详细信息请参阅 QML 全局对象 文档。

这些主机对象和函数始终可用,无论是否导入了任何模块。

JavaScript 对象和函数

QML引擎支持的JavaScript对象、函数和属性的列表可以在JavaScript对象和函数列表中找到。

请注意,QML对原生对象进行了以下修改:

  • 一个 arg() 函数被添加到 String 原型中。

  • 本地化感知的转换函数被添加到DateNumber原型中。

此外,QML还扩展了instanceof函数的行为,以允许对QML类型进行类型检查。这意味着你可以使用它来验证一个变量确实是你期望的类型,例如:

JavaScript 环境限制

QML 对 JavaScript 代码实现了以下限制:

  • 写在.qml文件中的JavaScript代码不能修改全局对象。而写在.js文件中的JavaScript代码可以修改全局对象,并且这些修改在imported后对.qml文件可见。

    在QML中,全局对象是常量——现有的属性不能被修改或删除,也不能创建新的属性。

    大多数JavaScript程序不会有意修改全局对象。然而,JavaScript自动创建未声明的变量是对全局对象的隐式修改,这在QML中是被禁止的。

    假设a变量在作用域链中不存在,以下代码在QML中是非法的:

    // 非法修改未声明的变量
    a = 1;
    for (var ii = 1; ii < 10; ++ii)
        a = a * ii;
    console.log("Result: " + a);
    

    可以简单地将其修改为以下合法代码。

    var a = 1;
    for (var ii = 1; ii < 10; ++ii)
        a = a * ii;
    console.log("Result: " + a);
    

    任何试图修改全局对象的尝试——无论是隐式还是显式——都会导致异常。如果未捕获,这将导致打印警告,其中包含违规代码的文件和行号。

  • 全局代码在缩减的作用域中运行。

    在启动期间,如果QML文件包含带有“全局”代码的外部JavaScript文件,它将在仅包含外部文件本身和全局对象的作用域中执行。也就是说,它将无法访问它通常可以访问的QML对象和属性。

    允许仅访问脚本局部变量的全局代码。这是一个有效的全局代码示例。

    var colors = [ "red", "blue", "green", "orange", "purple" ];
    

    访问QML对象的全局代码将无法正确运行。

    // 无效的全局代码 - "rootObject"变量未定义
    var initialPosition = { rootObject.x, rootObject.y }
    

    此限制存在是因为QML环境尚未完全建立。要在环境设置完成后运行代码,请参阅应用程序启动代码中的JavaScript

  • 在大多数上下文中,this 的值在 QML 中是未定义的。

    当从 JavaScript 绑定属性时,支持 this 关键字。在 QML 绑定表达式、QML 信号处理程序和 QML 声明的函数中,this 指的是作用域对象。在所有其他情况下,this 的值在 QML 中是未定义的。

    要引用特定对象,请提供 id。例如: