变量未定义/超出范围

时间:2013-11-28 03:25:41

标签: javascript

这是范围问题,对吗?

编辑:http://jsfiddle.net/RPwLK/7/

在以下函数的第38行,其中displayBossMessage()本身被调用,变量“boss”似乎超出了范围。它应该包含当前boss的名称(字符串),当调用该函数时,它应该将它放回“boss”参数中。

但老板似乎总是未定义。我已经尝试在创建jQuery监听器之前创建一个变量,看它是否在范围内,但看起来好像不是。

或许我只是在一个缓慢的一天。 ; P

function displayBossMessage(boss,message,options,timer){
    boss = bosses[boss];

    //clear any possible lingering text/buttons
    $(boss.messagebox).text('');
    $(boss.optionsbox).text('');
    displayMessage_CurrentBoss = boss;

    //if no options provided, set a default "continue" button
    if(options == ''){
        options = {
            'default' : {
                'text' : 'Continue',
                'func' : function(){}
            }
        }
    }

    $('#container div').hide();
    $(boss.div).fadeIn(1500);

    writeMessage(message,$(boss.messagebox),0);

    setTimeout(function(){
        $(boss.optionsbox).fadeIn(1000);
    },3000);

    //"listen" for a choice
    var i = 0;
    for(option in options){
        $(boss.optionsbox).html($(boss.optionsbox).html() + '<button name="'+ i +'">'+ options[option].text +'</button> &nbsp;');

        $(document).on('click', (boss.div)+' button[name="'+i+'"]', function(){
            options[option].func();

            //close message screen or show defined response
            if(typeof options[option].response != 'undefined'){
                displayBossMessage(boss,options[option].response,'',true);
            }else{
                $(boss.div).hide();
                $('#container div').fadeIn(1500);
            }

        });
    }

    if(timer){
        //if they are afk/don't click after a minute, do it for them
        setTimeout(function(){
            $(boss.div+' button[name="0"]').click();
        },60000);
    }
}

希望我没有完全忘记并且错过了这么简单的事情。

* 编辑:老板变量(全局)*

1 个答案:

答案 0 :(得分:1)

更新了包含两种解决方案的#11的jsfiddle修订链接

看起来这可能是一个工作小提琴:http://jsfiddle.net/RPwLK/11/

一个小问题:第30行有一个额外的'和(第二个)alert调用 - 字符串文字未正确关闭(或者另一个正在打开)。之后,我能够调查并得出以下结论(2个问题)......


第一个问题是变量覆盖

function displayBossMessage(boss,message,options,timer){
    boss = bosses[boss]; // this line, boss was a string, now it will be an object

以后在同一个函数中的用法:

if(typeof options[option].response != 'undefined'){
    displayBossMessage(boss,options[option].response,'',true); // first arg is now an object

解决方案是创建对原始boss的引用,如果它是一个字符串:

function displayBossMessage(boss,message,options,timer){
    var origBoss = boss; // let's remember what it was in its original string form
    boss = bosses[boss];

并像这样使用它:

if(typeof options[option].response != 'undefined'){
    displayBossMessage(origBoss,options[option].response,'',true); // now we're dealing with a string ref

第二个问题是option循环中对for的引用。它总是引用 last 值,因为$(document).on('click'...总是被延迟(异步)。有很多方法可以解决这个问题。我选择使用bind并传入一个参数,并为每个特定的迭代传递option的值。

请注意,原始option位于异步函数中,但不在闭包中(for不是闭包):

for(option in options){
    //...
    $(document).on('click', (boss.div)+' button[name="'+i+'"]', function(){
        options[option].func(); // here option is always the last item in options

因此,在单击处理程序的回调函数中引入一个方便地称为option的参数:

$(document).on('click', (boss.div)+' button[name="'+i+'"]', function(option){ // here
    options[option].func(); // and now option is whatever the argument value is

并且不要忘记通过bind:

在函数声明中传递它
    $(document).on('click', (boss.div)+' button[name="'+i+'"]', function(option){
        options[option].func();
        // ...
    }.bind(this,option)); // here we're passing whatever option is for the specific iteration as the first argument of the callback function

注意,this只是范围,第一个后面的bind (see MDN)的每个后续参数都对应于函数定义中的参数。