2

I have a questions regarding variable scope in Javascript. I have a series of scripts on a webpages loading at different times. I need a global object called MyVar for example to be accessible to them all. I want to avoid redefining it but I guess it has to be defined at some point by the first script. My question is is using var MyVar = MyVar || {} a solution?

Thanks

 /**
 * Script 1
 */


var MyVar = MyVar || {};
MyVar.config = {
    x : 2,
    y : 3
};


/**
* Script 2
*/

//is this correct?
var MyVar = MyVar || {};
//to which MyVar am I assigning the apple property?
MyVar.apple = 'red';

UPDATE

Great answers so far guys thanks.

One last part though, what is the second var statement doing when I repeat var MyVar = MyVar || {}; for the second time? Is it creating a new var in the global scope called MyVar that is assigned the value of the existing MyVar ?

Other posters are right to assume I have these scripts loading synchronously in <script> tags however due to division of labour I create the scripts then don't control when and how they are loaded so need a fool-proof method to create / utilize my MyVar object.

Thanks

ic3b3rg
  • 14,629
  • 4
  • 30
  • 53
JackMahoney
  • 3,423
  • 7
  • 32
  • 50
  • 1
    Check out [this question about best practices when dealing with global variables](http://stackoverflow.com/q/5063878/562906) – sinelaw Jan 10 '13 at 23:27
  • 1
    Yes, your code will work. Yes, you should avoid globals whenever possible. – wless1 Jan 10 '13 at 23:30
  • Read `var MyVar = MyVar || {};` as `var MyVar = MyVar if it exists (and isn't equal to false or 0) , or a new object if it doesn't`. – ic3b3rg Jan 11 '13 at 00:38

4 Answers4

2

Your code is correct and will probably work as expected, but bear in mind the scope in which MyVar is created. Assuming your files are as posted, they would create MyVar within the window scope (assuming a browser context). If one of them was wrapped in an anonymous function, as is common practice with the Module Pattern, MyVar would only be created within the scope of that function:

(function() {
    var MyVar = MyVar || {};
    // If MyVar doesn't already exist in the global context,
    // the current MyVar reference will only be scoped to this function.
})();

A better pattern to use is:

var MyVar = window.MyVar || (window.MyVar = {});

This will ensure it is always created, and referenced, from the global scope. You could even pass in the context in order to make future refactorings easier:

(function(context) {
    var MyVar = context.MyVar || (context.MyVar = {}));
})(window);
roryf
  • 29,592
  • 16
  • 81
  • 103
  • Thanks. So in `var MyVar = window.MyVar` is `MyVar` a reference to `window.MyVar` or is it an assignment of value? – JackMahoney Jan 11 '13 at 00:23
  • If `window.MyVar` exists, your local `MyVar` variable will be a reference to it. If it doesn't exist, the second part `|| (window.MyVar = {})` will create a new object, assign it to `window.MyVar` and return the reference which will be assigned to the local `MyVar` variable. – roryf Jan 11 '13 at 09:52
2

I have a series of scripts on a webpages loading at different times

Is any of them loaded asynchronously? If it's just a series of <script> tags, they will be loaded synchronously, in sequence.

to which MyVar am I assigning the apple property?

If you declare MyVar on the global scope every time, there will be only one MyVar. The apple property will be created on the existing variable, if it exists, or in the empty object created with var MyVar = MyVar || {}; if it doesn't.

Bottom line: after the first var MyVar = MyVar || {};, following declarations will be ignored, and new properties will be appended to the existing variable. Just be careful not to overwrite existing properties.

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • This is a good explanation. One last part though, what is the second var statement doing when I repeat `var MyVar = MyVar || {};` for the second time? Is it creating a new var in the global scope called `MyVar` that is assigned the value of the existing `MyVar` ? – JackMahoney Jan 11 '13 at 00:25
  • It will do `MyVar = MyVar` (which is basically doing nothing at all). – bfavaretto Jan 11 '13 at 00:30
  • 1
    @JackMahoney - To clarify, only the first `var` definition for a particular variable name actually defines that variable. Any subsequent `var` statement for the same variable name essentially does nothing; specifically, it does *not* create a new variable with the same name. – David R Tribble Nov 10 '16 at 17:00
1

This is easy to test:

var MyVar = MyVar || {};
MyVar.config = {
    x : 2,
    y : 3
};

console.log(MyVar);

var MyVar = MyVar || {};
MyVar.apple = 'red';

console.log(MyVar);
ic3b3rg
  • 14,629
  • 4
  • 30
  • 53
  • What if the order the scripts are referenced is changed? Your example is not good defensive programming. – roryf Jan 10 '13 at 23:52
  • I read it as two separate window-level scripts. I suppose they could be reordered within the html, but I think that goes beyond Jack's question. – ic3b3rg Jan 10 '13 at 23:59
  • @ic3b3rg you're right they are two separate scripts and I don't know what order they will be in – JackMahoney Jan 11 '13 at 00:21
  • 1
    In that case, @roryf's advice is better, although you might find my suggestion to test with console.log helpful. – ic3b3rg Jan 11 '13 at 00:27
0

This is how I do it:

window.myVar||(window.myVar={});

This way you are not re-declaring the variable if it already exists.

Christophe
  • 27,383
  • 28
  • 97
  • 140