이 페이지에서

범위 및 이름 해결

QML 속성 바인딩, 인라인 함수 및 가져온 JavaScript 파일은 모두 JavaScript 범위 내에서 실행됩니다. 범위는 식이 어떤 변수에 접근할 수 있는지, 그리고 두 개 이상의 이름이 충돌할 때 어떤 변수가 우선권을 가지는지를 제어합니다.

자바스크립트의 내장 범위 메커니즘은 매우 단순하기 때문에, QML은 QML 언어 확장에 더 자연스럽게 부합하도록 이를 확장합니다.

자바스크립트 범위

QML의 범위 확장은 자바스크립트의 자연스러운 범위 지정 방식에 간섭하지 않습니다. 자바스크립트 프로그래머는 QML에서 함수, 속성 바인딩 또는 가져온 자바스크립트 파일을 프로그래밍할 때 기존의 지식을 재사용할 수 있습니다.

다음 예제에서, ` addConstant() ` 메서드는 QML 객체의 ` a ` 및 ` b ` 속성 값과 관계없이 프로그래머가 예상한 대로 전달된 매개변수에 13을 더할 것입니다.

QtObject {
    property int a: 3
    property int b: 9

    function addConstant(b) {
        var a = 13;
        return b + a;
    }
}

QML이 자바스크립트의 일반적인 범위 규칙을 준수한다는 사실은 바인딩에서도 마찬가지입니다. 이 완전히 엉망진창이고 끔찍한 바인딩은 QML 객체의 ` a ` 속성에 12를 할당할 것입니다.

QtObject {
    property int a

    a: { var a = 12; a; }
}

QML 내의 모든 자바스크립트 표현식, 함수 또는 파일은 각각 고유한 변수 객체를 가집니다. 한 곳에서 선언된 지역 변수는 다른 곳에서 선언된 지역 변수와 절대 충돌하지 않습니다.

타입 이름과 임포트된 자바스크립트 파일

QML 문서에는 해당 문서에서 사용할 수 있는 유형 이름과 JavaScript 파일을 정의하는 import 문이 포함됩니다. 유형 이름은 QML 선언 자체에서 사용될 뿐만 아니라, JavaScript 코드가 부착된 속성 및 열거형 값에 접근할 때도 사용됩니다.

import의 효과는 중첩된 인라인 컴포넌트에 포함된 경우를 포함하여, QML 문서 내의 모든 속성 바인딩과 자바스크립트 함수에 적용됩니다. 다음 예제는 몇 가지 열거형 값에 접근하고 임포트된 자바스크립트 함수를 호출하는 간단한 QML 파일을 보여줍니다.

import QtQuick 2.0
import "code.js" as Code

ListView {
    snapMode: ListView.SnapToItem

    delegate: Component {
        Text {
            elide: Text.ElideMiddle
            text: "A really, really long string that will require eliding."
            color: Code.defaultColor()
        }
    }
}

바인딩 범위 객체

속성 바인딩을 가진 객체를 해당 바인딩의 범위 객체라고 합니다. 다음 예제에서 Item 객체가 바인딩의 범위 객체입니다.

Item {
    anchors.left: parent.left
}

바인딩은 한정자 없이 범위 객체의 속성에 접근할 수 있습니다. 앞의 예제에서 바인딩은 어떤 형태의 객체 접두사도 필요로 하지 않고 Item 의 parent 속성에 직접 접근합니다. QML은 자바스크립트에 대해 보다 구조화된 객체 지향적 접근 방식을 도입하므로, 자바스크립트의 this 속성을 사용할 필요가 없습니다.

바인딩을 통해 부착 속성에 접근할 때는 스코프 객체와의 상호작용으로 인해 주의가 필요합니다. 개념적으로 부착 속성은 모든 객체에 존재하지만, 실제로는 그중 일부에만 영향을 미칩니다. 따라서 한정되지 않은 부착 속성 읽기는 항상 스코프 객체의 부착 속성으로 해결되는데, 이는 프로그래머가 의도한 바와 항상 일치하지는 않습니다.

예를 들어, ` PathView ` 타입은 경로 내 위치에 따라 델리게이트에 보간된 값 속성을 부착합니다. ` PathView `는 델리게이트 내 루트 객체에만 이러한 속성을 의미 있게 부착하므로, 해당 속성에 접근하는 하위 객체는 아래와 같이 루트 객체를 명시적으로 지정해야 합니다.

PathView {
    delegate: Component {
        Rectangle {
            id: root
            Image {
                scale: root.PathView.scale
            }
        }
    }
}

만약 Image 객체가 root 접두사를 생략했다면, 의도치 않게 자체에 연결된 설정되지 않은 PathView.scale 속성에 접근하게 될 것입니다.

컴포넌트 범위

QML 문서 내의 각 QML 컴포넌트는 논리적 범위를 정의합니다. 각 문서에는 적어도 하나의 루트 컴포넌트가 있지만, 그 외에 인라인 하위 컴포넌트를 포함할 수도 있습니다. 컴포넌트 범위는 해당 컴포넌트 내의 객체 ID와 컴포넌트의 루트 객체 속성의 합집합입니다.

Item {
    property string title

    Text {
        id: titletype
        text: "<b>" + title + "</b>"
        font.pixelSize: 22
        anchors.top: parent.top
    }

    Text {
        text: titletype.text
        font.pixelSize: 18
        anchors.bottom: parent.bottom
    }
}

위의 예제는 상단에 리치 텍스트 제목 문자열을 표시하고, 하단에 동일한 텍스트의 축소된 버전을 표시하는 간단한 QML 컴포넌트를 보여줍니다. 첫 번째 Text 유형은 표시할 텍스트를 구성할 때 컴포넌트의 title 속성에 직접 접근합니다. 루트 유형의 속성에 직접 접근할 수 있기 때문에 컴포넌트 전체에 데이터를 분배하는 것이 매우 간단합니다.

두 번째 Text 타입은 ID를 사용하여 첫 번째 타입의 텍스트에 직접 접근합니다. ID는 QML 프로그래머가 명시적으로 지정하므로, 항상 다른 속성 이름보다 우선합니다( JavaScript 범위 내의 속성 이름은 예외). 예를 들어, 앞서 예제에서 바인딩의 scope 객체에 titletype 속성이 있는 드문 경우라도, titletype ID가 여전히 우선시됩니다.

컴포넌트 인스턴스 계층 구조

QML에서 컴포넌트 인스턴스는 각자의 컴포넌트 스코프를 서로 연결하여 스코프 계층 구조를 형성합니다. 컴포넌트 인스턴스는 상위 컴포넌트의 컴포넌트 스코프에 직접 접근할 수 있습니다.

이를 가장 쉽게 설명할 수 있는 방법은, 컴포넌트 범위가 암시적으로 외부 컴포넌트의 자식으로 지정되는 인라인 하위 컴포넌트를 사용하는 것입니다.

Item {
    property color defaultColor: "blue"

    ListView {
        delegate: Component {
            Rectangle {
                color: defaultColor
            }
        }
    }
}

컴포넌트 인스턴스 계층 구조를 통해 델리게이트 컴포넌트의 인스턴스는 Item 유형의 defaultColor 속성에 접근할 수 있습니다. 물론, 델리게이트 컴포넌트에 defaultColor 이라는 속성이 있었다면 해당 속성이 우선 적용되었을 것입니다.

컴포넌트 인스턴스 범위 계층 구조는 비인라인 컴포넌트에도 적용됩니다. 다음 예제에서 TitlePage.qml 컴포넌트는 두 개의 TitleText 인스턴스를 생성합니다. TitleText 타입이 별도의 파일에 있더라도, TitlePage 내에서 사용될 때는 여전히 title 속성에 접근할 수 있습니다. QML은 동적 스코핑을 지원하는 언어이므로, 사용 위치에 따라 title 속성의 해결 결과가 달라질 수 있습니다.

// TitlePage.qml
import QtQuick 2.0
Item {
    property string title

    TitleText {
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property int size
    text: "<b>" + title + "</b>"
    font.pixelSize: size
}

동적 스코핑은 매우 강력하지만, QML 코드의 동작이 예측하기 어려워지지 않도록 주의해서 사용해야 합니다. 일반적으로 두 컴포넌트가 이미 다른 방식으로 밀접하게 결합되어 있는 경우에만 사용해야 합니다. 재사용 가능한 컴포넌트를 구축할 때는 다음과 같이 속성 인터페이스를 사용하는 것이 바람직합니다.

// TitlePage.qml
import QtQuick 2.0
Item {
    id: root
    property string title

    TitleText {
        title: root.title
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        title: root.title
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property string title
    property int size

    text: "<b>" + title + "</b>"
    font.pixelSize: size
}

다른 QML 컴포넌트에서 루트 객체 id 를 참조하지 마십시오

루트 객체가 정의된 QML 파일 외부에서 id 에 접근하지 마십시오. id 값은 동일한 문서 내에서만 유효하며, 다른 컴포넌트에서 이를 참조하면 캡슐화와 컴포넌트 경계가 깨집니다.

// Main.qml
import QtQuick

Item {
    id: root
    CustomItem { }
}

// CustomItem.qml
import QtQuick

Rectangle {
    width: root.width
    height: root.height / 2
    color: "red"
}

위의 예제에서 root 은 CustomItem.qml 에 선언되어 있지 않습니다. CustomItem 이 root 가 존재하는 컨텍스트에서 인스턴스화되기 때문에 코드는 여전히 작동하며, 이는 QML의 동적 범위 규칙에 의해 허용됩니다. 그러나 이는 외부 범위에 대한 암시적 의존성을 생성하여, 컴포넌트가 동적으로 로드되거나 다른 컨텍스트에서 사용될 때 신뢰성을 떨어뜨리고 재사용하기 어렵게 만듭니다. 또한 이 패턴은 미묘한 버그를 유발할 수도 있습니다. 예를 들어, 범위 체인 내의 다른 객체가 동일한 ` id`을 사용하면, 예상된 객체를 가릴 수 있어 예기치 않은 동작이 발생할 수 있습니다.

컴포넌트를 안정적이고 재사용 가능하게 만들려면, 명시적 속성, 속성 별칭 또는 신호를 통해서만 외부 상태에 접근해야 합니다. 외부 범위의 ` id ` 값에 의존하는 것은 피하십시오.

다음 예제는 동적 스코핑을 명시적인 컴포넌트 API로 대체합니다.

// Main.qml
import QtQuick
import QtQuick.Window

Window {
    id: root
    width: 400
    height: 300
    visible: true

    CustomItem {
        width: root.width
        height: root.height
        boxColor: "blue"
    }
}

// CustomItem.qml
import QtQuick

Item {
    id: container
    property alias boxColor: rect.color

    Rectangle {
        id: rect
        width: container.width
        height: container.height / 2
        color: "red"
    }
}

컴포넌트 내부에서 ` id `로 선언된 모든 내부 객체에도 동일한 규칙을 적용하십시오.

// MyItem.qml
import QtQuick

Item {
    Item {
        id: internalCounter
        property int count: 5
    }
}

// main.qml
import QtQuick

MyItem {
    Component.onCompleted: {
        console.log(internalCounter.count);
    }
}

위의 예제에서, 다른 QML 파일에서 id 인 internalCounter 에 액세스하면 ReferenceError 가 발생합니다. 이는 id 가 문서 로컬(document-local)이며, 선언된 QML 파일 외부에서는 액세스할 수 없기 때문입니다.

내부 객체가 상태나 동작을 노출해야 하는 경우, 속성, 속성 별칭 또는 신호를 통해 명시적으로 노출하십시오.

다음 예제는 문서 내(document-local) id 에 대한 직접적인 접근에 의존하는 대신, 명시적인 컴포넌트 API를 통해 내부 상태를 노출합니다.

// MyItem.qml
import QtQuick

Item {
    Item {
        id: internalCounter
        property int count: 5
    }
    property alias internalCount: internalCounter.count
}

// main.qml
import QtQuick

MyItem {
    Component.onCompleted: {
        console.log(internalCount);
    }
}

이를 통해 명확한 컴포넌트 경계를 유지하고 확장성 및 테스트 용이성을 높일 수 있습니다.

재정의된 속성

QML에서는 객체 선언에서 정의된 속성 이름이, 해당 객체를 상속하는 다른 객체 선언 내에서 선언된 속성에 의해 재정의될 수 있습니다. 예를 들면 다음과 같습니다.

// Displayable.qml
import QtQuick 2.0
Item {
    property string title
    property string detail

    Text {
        text: "<b>" + title + "</b><br>" + detail
    }

    function getTitle() { return title }
    function setTitle(newTitle) { title = newTitle }
}

// Person.qml
import QtQuick 2.0
Displayable {
    property string title
    property string firstName
    property string lastName

    function fullName()  { return title + " " + firstName + " " + lastName }
}

여기서 title 라는 이름은 Displayable의 출력 텍스트 제목과 Person 객체의 호칭 모두에 부여됩니다.

재정의된 속성은 참조되는 범위에 따라 해결됩니다. Person 컴포넌트의 범위 내부에서, 또는 Person 컴포넌트의 인스턴스를 참조하는 외부 범위에서 title 은 Person.qml 내에 선언된 속성으로 해결됩니다. fullName 함수는 Person 내에 선언된 title 속성을 참조합니다.

그러나 Displayable 컴포넌트 내에서는 title 가 Displayable.qml에 선언된 속성을 가리킵니다. getTitle() 및 setTitle() 함수와 Text 객체의 text 속성에 대한 바인딩은 모두 Displayable 컴포넌트에 선언된 title 속성을 가리킵니다.

이름이 같더라도 두 속성은 완전히 별개입니다. 한 속성에 대한 onChanged 신호 핸들러는 같은 이름을 가진 다른 속성의 변경에 의해 트리거되지 않습니다. 두 속성 중 하나에 대한 별칭은 둘 중 하나를 참조하지만, 둘 다를 참조하지는 않습니다.

JavaScript 전역 객체

QML은 혼동을 방지하기 위해 전역 객체의 속성과 충돌하는 유형, ID 및 속성 이름을 허용하지 않습니다. 프로그래머는 ` Math.min(10, 9) `가 항상 예상대로 작동할 것이라고 확신할 수 있습니다!

자세한 내용은 JavaScript 호스트 환경을 참조하십시오.

© 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.