QML 值类型和序列引用
QML 值类型和 QML 序列类型必然按值传递。与QML 对象类型不同,它们本身没有独立的身份,而只能作为其他对象或值的属性,或作为方法返回的值来访问。每次此类访问都会隐式创建一份副本。然而,在 JavaScript 中,一切都是对象。 JavaScript 中并不存在“值类型”这一概念。例如,如果在 JavaScript 中执行 `font.bold = true `,无论 `font ` 的值为何,我们都会预期 `font ` 的 `bold ` 属性会被设置。但请考虑以下代码片段:
import QtQuick
Text {
onSomethingHappened: font.bold = true
}在此情况下,我们知道 `font ` 是一个值类型。访问它会通过调用 `Q_PROPERTY` 的获取器来创建一个本地副本。然后我们可以对其设置 `bold ` 属性,但这通常只会影响该副本,而不会影响原始的 `Q_PROPERTY`。
为解决此问题,QML 引入了引用(reference)的概念。 当您从属性中检索值类型或序列类型的实例时,QML 引擎会同时记住该属性及其值本身。如果值被修改,则会将其写回属性中。这营造出对象具有独立身份的错觉,并使上述情况以及许多其他情况都能正常工作。
不过,这种机制的开销可能相当大。如果一个序列以Q_PROPERTY 的形式暴露出来,通过索引访问序列中的任何值都会导致从属性中读取整个序列数据。随后,才从这些序列数据中提取出单个元素。同样地,修改序列中的任何值也会导致读取序列数据。 随后执行修改操作,并将修改后的序列写回属性。如果相关类型是隐式共享的,读取操作的开销相对较小。而修改操作总是会产生至少一次深度复制。
若从Q_INVOKABLE 函数中返回序列或值类型的实例,则可避免此类开销。返回值不会与任何属性相关联,也不会被写回。
对象类型的序列默认作为QQmlListProperty 传递。QQmlListProperty 并非真正的容器,而仅仅是对某个顺序存储的视图或引用。因此,QQmlListProperty 不受此影响。不过,您可以使用QML_SEQUENTIAL_CONTAINER 为对象注册其他序列类型,这些类型将受到影响。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.