QML: лямбда-функция работает неожиданно

Я думал, что QML поддерживает лямбда-функции из-за поддержки анонимных функций JavaScript и того факта, что функции являются объектами первого класса, но они не работают так, как я ожидал. Возьмите этот код:

Item {
    property var items: []

    function handler( item ) {
        console.log( item );
    }

    Component.onCompleted: {
        for ( var i = 0; i < 3; ++i ) {
            var item = someObj.createObject();
            item.someValueChanged.connect( function() {
                handler( item ); } );

            items.push( item );
            console.log( "Adding:", item );
        }
    }

    Component {
        id: someObj

        Item {
            property bool someValue: false

            Timer {
                running: true
                onTriggered: {
                    parent.someValue = true;
                }
            }
        }
    }
}

Я пытаюсь использовать лямбда function() { handler( item ); } Так что, когда someObj::someValueChanged сигнал испущен испуская деталь передан к

2 ответов


попробуйте что-то вроде этого:

item.someValueChanged.connect(function(temp) {
    return function() {
        handler(temp)}
}(item))

интуитивно понятные, верно? : D

Если бы JS использовал "область блока", было бы 3 разных items ссылается на каждую итерацию цикла, и она будет "работать так, как ожидалось". Но с "областью действия" существует только один item referenced, и он ссылается на его конечное значение, поэтому необходимо использовать этот хак для "захвата" каждого значения во времени.


ответ dtech решает проблему (спасибо!) но мы можем упростить его, чтобы было яснее, что именно происходит. "Внутренняя" функция должна быть анонимной, но "внешняя" не нужна. Использование нормальной функции для внешней делает код намного проще для понимания и легче для его самопроверки, поскольку функция имеет имя. Внешняя функция создает обработчик сигнала, поэтому эквивалентный код может быть:

var signal_handler = create_signal_handler(item);
item.someValueChanged.connect(signal_handler);

...

function create_signal_handler(item)
{
    return function() { return handler(item); }
}