尽管仍然在范围内,Javascript对象会失去状态

时间:2014-02-02 10:30:46

标签: javascript jquery

我有一个简单的Javascript程序,用于在每个项目的指定时间内滚动文本项列表。大多数代码都正常工作,但是我的对象没有保留状态会遇到问题。

我有一个BuildManager对象,它加载一个构建(一组指令),然后重新组装一个时间delta和DOM对象的数组。稍后,按钮的单击功能可以引用此对象的实例,从而检查其当前构建。 BuildManager实例正在构建数组,但是当按钮调用的函数运行时,BuildManager实例会说它的数组长度为零。我知道这是范围或类似的问题,但我找不到哪里。在测试期间,我注意到如果我使数组全局而不是对象属性,那么它就可以工作,因为全局变量保留了修改。

TLDR: document.ready函数创建一个名为manager的Build Manager,并设置监听器。我单击#load-build-button,它在manager中成功创建了数组(已验证)。稍后我点击#start-build-button失败,因为当它调用manager.getNextStepStartingTime()时,管理器active_build的长度为0。

这里的代码简化为必要的:

var BuildManager = function() {
    var current_array = [
        [5, "This is the step with the number: 1"],
        [10, "This is the step with the number: 2"],
        [15, "This is the step with the number: 3"],
        [25, "This is the step with the number: 4"],
        [40, "This is the step with the number: 5"],
        [45, "This is the step with the numberasdfadsfasdfasf: 6"],
        [47, "This is the step with the number: 7"],
        [49, "This is the step with the number: 8"],
        [50, "This is the step with the number: 9"],
        [60, "This is the step with the number: 10"],
        [120, "This is the step with the number: 11"],
        [130, "This is the step with the number: 13"],
        [133, "This is the step with the number: 14"],
        [135, "This is the step with the numbasdfasdfadsfasfder: 15"],
        [137, "This is the step with the number: 16"],
        [139, "This is the step with the number: 17"],
        [145, "This is the step with the number: 18"]
    ];

    this.active_build = [];

    this.loadBuild = function() {
        $(".build-item").remove();
        this.active_build = [];
        for (var i = 0, len = current_array.length; i < len; i++) {
            $(".build-list").append("<div class='build-item'>" + current_array[i][1] + "</div>\n");
            this.active_build.push([current_array[i][0], $(".build-item:contains('"+ current_array[i][1] +"')")]);
        }
    };

    this.getNextStepStartTime = function() {
        return this.active_build[0][0];
    };

    this.getNextStepHeight = function() {
        return this.active_build[0][1].height;
    };

    this.completeStep = function() {
        this.active_build.shift();
    };
};

$(document).ready(function() {
    /* Initialize Jquery items */
    $("input[type=button]").button();

    /* High level data because setInterval doesn't work with objects */
    var total_time_passed = 0;
    var manager = new BuildManager();

    function timerFunction() {
        /* If this isn't the first time here, we've just completed a step, so let the manager know */
        if (total_time_passed > 0) {
            manager.completeStep();
        }

        /* Find out how long until the next step is complete, and animate to it */
        var time_to_next = manager.getNextStepStartTime()-total_time_passed;
        if (time_to_next > 0) {
            var build_list = $(".build-list");
            var prev_pos = parseInt(build_list.css("margin-top"));
            build_list.animate({marginTop: prev_pos - manager.getNextStepHeight()}, time_to_next*1000);
        }

        /* Set this function to run again once the target time has been reached */
        total_time_passed += time_to_next;
        setTimeout(timerFunction, time_to_next*1000);
    }

    function startBuild() {
        timerFunction();
    }

    function stopBuild() {
        //does nothing yet
    }

    /* Setup Click Handlers */
    $("#load-build-button").click(manager.loadBuild);
    $("#start-build-button").click(startBuild);
    $("#stop-build-button").click(stopBuild);
});

1 个答案:

答案 0 :(得分:3)

manager.loadBuild是对函数的引用,该函数不包含有关manager的信息。您需要将引用传递给绑定到范围的函数:

$("#load-build-button").click(manager.loadBuild.bind(manager));

或者,您可以在声明函数时绑定函数:

this.loadBuild = function() {
    $(".build-item").remove();
    this.active_build = [];
    for (var i = 0, len = current_array.length; i < len; i++) {
        $(".build-list").append("<div class='build-item'>" + current_array[i][1] + "</div>\n");
        this.active_build.push([current_array[i][0], $(".build-item:contains('"+ current_array[i][1] +"')")]);
    }
}.bind(this); // bound!