5

I load the same script in my page many times. I have some trouble on decide which is loaded first/after in my website, due to the async/load functions.

So, I'd like to put a global variable that count, when the script is loaded, the order of them.

So myScript.js will start with :

(function () {
    var privateNumberScriptLoaded;

    if (numberScriptLoaded === undefined) {
        numberScriptLoaded = 0;
    }
    else {
        numberScriptLoaded = numberScriptLoaded + 1;
    }

    privateNumberScriptLoaded = numberScriptLoaded;
    console.log(privateNumberScriptLoaded);
})();

but when I load it with :

<script src="http://www.mywebsite.com/widget/myScript.js?type=normal" type="text/javascript"></script>
<script src="http://www.mywebsite.com/widget/myScript.js?type=rotation" type="text/javascript"></script>

I get (for two times) numberScriptLoaded is not defined.

How can I resolve this trouble? In fact I'll "create" a global variable in my website if it doesnt exist. Than increment it and store in a "private" variable for each script, so I can save the order of the execution for each script.

markzzz
  • 47,390
  • 120
  • 299
  • 507
  • possible duplicate of [How can I check whether a variable is defined in JavaScript?](http://stackoverflow.com/questions/519145/how-can-i-check-whether-a-variable-is-defined-in-javascript) – Felix Kling Jun 01 '12 at 13:17

7 Answers7

10

At present, your script falls prey to The Horror of Implicit Globals. I'd recommend not doing that.

You have three options:

  1. As all global variables end up as properties on window, you could use window explicitly:

    if (!window.numberScriptLoaded) {
        window.numberScriptLoaded = 1; // 1, not 0
    }
    else {
        ++window.numberScriptLoaded;
    }
    

    Unlike the code without the window. prefix, that won't throw a ReferenceError, because looking up a property on an object works differently from resolving a freestanding identifier.

    Live demo | demo page source | source of script it loads

  2. Always put var numberScriptLoaded; (with no initializer) at global scope in your script, e.g. outside your scoping function:

    var numberScriptLoaded; // No initializer (no = 0 or anything)
    

    On the first load, this will create the variable; on subsequent loads, it's a no-op. Then you can do this without a ReferenceError:

    if (!numberScriptLoaded) {
        numberScriptLoaded = 1; // 1, not 0
    }
    else {
        ++numberScriptLoaded;
    }
    

    Live demo | demo page source | source of script it loads

  3. Use typeof. If you take the typeof a variable that doesn't exist, you don't get a ReferenceError; you get "undefined". Then you can create it via the window. prefix (so you're not falling prey to The Horror).

    if (typeof numberScriptLoaded === "undefined") {
        // Assigning to window.numberScriptLoaded creates the global
        window.numberScriptLoaded = 1; // 1, not 0
    }
    else {
        ++numberScriptLoaded;
    }
    

    Live demo | demo page source | source of script it loads

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • `2 - Always put var numberScriptLoaded; (with no initializer) at global scope in your script.` : i need this variable "global" for the whole website, so the next script loaded can access to this variable. – markzzz Jun 01 '12 at 13:46
  • P.S. in fact, except "typeof", I'm following the 3° option. What's wrong? – markzzz Jun 01 '12 at 13:47
  • @markzzz: Re your first comment: Right, that's why I'm saying you put it at global scope. So it's a global. Re your second comment: See what I wrote; without `typeof`, you're trying to reference an identifier that isn't in scope, resulting in a `ReferenceError`. – T.J. Crowder Jun 01 '12 at 13:56
  • How can you put a variable in global scope without "var"? – markzzz Jun 01 '12 at 14:36
  • @markzzz: By assigning to a property on the global object, which is the container of all global variables. On browsers, there's a global variable, `window`, that refers to the global object. (It's a property the object uses to point to itself.) So `window.foo = 2;` creates a global variable called `foo` with the value `2`. I've added demos of all three options for you. – T.J. Crowder Jun 01 '12 at 15:45
  • Honestly I read in deep that article about "horror", but really, I don't understand why this "Horror". Using `window.numberScriptLoaded = 1` or `numberScriptLoaded = 1` in fact doesnt make any differences. So why using `window.`? Can you give to me an example? – markzzz Jun 08 '12 at 09:16
  • @markzzz: The horror doesn't primarily relate to whether you use `window` or not. Say you have a global variable called `label`. In a function, you try to set the value of this variable, and you write `lable = "Hi there";` ***Boom***, you have a hard-to-find, silent bug, because rather than doing what any reasonable system would do and throwing an error for the undefined symbol `lable`, classic JS just happily creates a new global called `lable`. Fortunately, the new strict mode fixes this error. But if you really meant to create an ad hoc global, using `window` helps make your intent clear. – T.J. Crowder Jun 08 '12 at 09:56
  • So, it's just a discussion about the easily on read code and find scope! Well, I've thought in some that generate error ;) – markzzz Jun 08 '12 at 10:15
4

You should use typeof

if (typeof numberScriptLoaded === 'undefined') {
xdazz
  • 158,678
  • 38
  • 247
  • 274
  • 1
    usually this work as well `window.jQuery === undefined`. What's the difference? – markzzz Jun 01 '12 at 12:50
  • 1) What's the point of using much slower === when typeof always returns string? 2) isn't `if(numberScriptLoaded===undefined)` a quicker/shorter/better solution? – meeDamian Jun 01 '12 at 12:53
  • 2
    The only difference is that `undefined` can be overwritten. `undefined = 5; window.jQuery === undefined;` compares the variable against 5 instead of testing if it is undefined. Since `undefined` is global, the fear is that a (stupid) library may overwrite it and you would not know. – apsillers Jun 01 '12 at 12:53
  • @chester1000 much slower? compare to what? – xdazz Jun 01 '12 at 12:54
  • @chester1000 `if(numberScriptLoaded===undefined)` will give you a undefined error. – xdazz Jun 01 '12 at 12:56
  • @chester1000 `===` is fast than `==`, the speed does not depends on how many `=` it has. :) – xdazz Jun 01 '12 at 12:57
  • @xdazz: You're right it will work only on object proporties: `var a={}; if(a.sth==undefined){}`. Also, therein fact is a performance difference between `==` and `===`, but previously I was wrong, `===` is faster, because it doesn't perform type conversion first. :) – meeDamian Jun 01 '12 at 13:02
  • Oh, yes, @xdazz brings up a good point -- understand the difference between a *variable name that has not been defiend* and an *existing variable whose type is `undefined`*. The check `myvar === undefined` will give an error if the variable named `myvar` has never been defined with `var myvar;` or similar. By contrast, `typeof` handles both cases just fine. – apsillers Jun 01 '12 at 13:03
  • @apsillers: As I said before, it works only with object fields, but if you'd like to check any variable that way, just use it as window property: `if( window.sth===undefined ) {` – meeDamian Jun 01 '12 at 13:08
  • @chester1000: Not *any* variable. Just global variables. – T.J. Crowder Jun 01 '12 at 14:00
  • 1
    @chester1000: *"1) What's the point of using much slower `===` when typeof always returns string?"* Slower than what? "*2) isn't `if(numberScriptLoaded===undefined)` a quicker/shorter/better solution?"* Not if `numberScriptLoaded` isn't in scope, no; that's the reason the OP is getting a `ReferenceError` thrown in the first place! – T.J. Crowder Jun 01 '12 at 14:01
2

Try

if ( 'undefined' === typeof numberScriptLoaded ) {
    numberScriptLoaded = 0;
} else {
    numberScriptLoaded = numberScriptLoaded + 1;
}
Sirko
  • 72,589
  • 19
  • 149
  • 183
1
myGlobalVar = typeof myGlobalVar == "undefined"? "New Value" : myGlobalVar;
myGlobalVar = typeof myGlobalVar == "undefined"? "Totally New Value" : myGlobalVar;
alert(myGlobalVar);

http://jsfiddle.net/8gnuwaah/2/

fahadash
  • 3,133
  • 1
  • 30
  • 59
0

Global variables are direct attributes of window object. So if you'd like to init global variable from anywhere just type:

window.variableName = "what_ever_you_want"
meeDamian
  • 1,143
  • 2
  • 11
  • 24
0

As a best practice and to prevent this type of errors, all variables should be initialized before being used in your script.

You should put:

var numberScriptLoaded;

Just before your closure and the error won't happen.

nebulousGirl
  • 1,364
  • 2
  • 13
  • 23
0

If you're going to use the window to store the global, then you can do it in a single line with:

window.numberScriptLoaded  = (window.numberScriptLoaded  || 0) + 1
Feiteira
  • 811
  • 8
  • 9