Javascript Variable Scope

2019-07-19 00:28发布

问题:

I'm having issues with a javascript global variable (called TimeStamp) not being defined onload...at least I think that's the problem.

I start with this, defining TimeStamp.

        $(document).ready(function(){
        // AddTest();
        var TimeStamp = null;
        waitForMsg();
    });

...waitForMsg then runs using TimeStamp and updated it on successful completion of the ajax call. At least that's the idea, but at the moment nothing runs because "TimeStamp is not defined"...even though I defined it earlier! (urgh).

If I re-define Timestamp within waitForMsg it just gets reset instead of using the updated value from the successfull ajax function.

    function waitForMsg(){


    $.ajax({
        type: "POST",
        url: "backend.php",
        async: true,
        cache: false,
        timeout:50000, /* Timeout in ms */
        data: "TimeStamp=" + TimeStamp,
        success: function(data){

            var json = eval('(' + data + ')');

            $('#TextHistory :last-child').after('<p>' + json['msg'] + '</p>');


            TimeStamp = json['timestamp'];


            setTimeout(
                'waitForMsg()', /* Request next message */
                1000            /* ..after 1 seconds */
            );
        },
        error: function(XMLHttpRequest, textStatus, errorThrown){

            $('#TextHistory :last-child').after('<p>' + errorThrown + '</p>');

            setTimeout(
                'waitForMsg()', /* Try again after.. */
                "15000");       /* milliseconds (15seconds) */
        },
    });
};

As always any help is greatly appreciated.

Dan.

回答1:

change

$(document).ready(function(){
    // AddTest();
    var TimeStamp = null;
    waitForMsg();
});

to

var TimeStamp = null;
$(document).ready(function(){
    // AddTest();
    waitForMsg();
});

That way the it will live in the global scope and not just in the scope of the ready function.

As a further note, you should change your setTimeout statements from the form setTimeout(string to eval,delay) to setTimeout(function reference to run, delay). like so:

setTimeout(waitForMsg,1000);

so you avoid the unnecessary eval call.

Further more, consider changing

var json = eval('(' + data + ')');

to

var json = JSON && JSON.parse ? JSON.parse(data) : eval('(' + data + ')');

so that you get the benefit of native JSON parsing in modern browsers.

Even better, let jQuery deserialize the JSON for you by adding dataType: 'json' as parameter on the ajax call :)



回答2:

Don't pass strings to be evaled. It is inefficient, hard to debug and breaks scope:

setTimeout('waitForMsg()',1000);

Do pass functions:

setTimeout(waitForMsg,1000);


回答3:

You have to define the var TimeStamp outside of any functions in the page scope.

When you define a variable within a code block it will be visible only at the same 'level' and it won't be visible within methods you call from that code block.

When you write a values to the TimeStamp variable within your ajax call (and without defining it with 'var') it will automatically define or reuse the TimeStamp variable in the page scope, however since you try to read the TimeStamp (data: "TimeStamp=" + TimeStamp) variable before you even write to it, then it will generate the 'is not defined' error.

Anyways: Consider the possibility to avoid usage of page-scope variables.