3

I'm writing a Javascript library that I hope to be able to minify with the Closure Compiler's ADVANCED_OPTIMIZATIONS option. The library has maybe two dozen global variables which set lower and upper range limits, string literals, etc.

To make these variable accessible from other source files and to avoid dead code removal, I have to "export" them. See Advanced Compilation and Externs.

Therefore, rather than declare variables with this syntax:

var fooMinValue = 10;

I plan to use this syntax:

 window['fooMinValue'] = 10;

I've tested this and it seems to work fine. My questions are, is there any downside to using this syntax and is it supported in all browsers released since IE 6? (Or should I be using a completely different technique altogether?)

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
Karl
  • 1,814
  • 1
  • 25
  • 37
  • 1
    In global code, you can use `this` to access the global object. Also if your names are alphanumerics, you don't need the bracket-notation: `this.fooMinValue = 10;`. – Šime Vidas Oct 26 '12 at 17:35
  • @ŠimeVidas FYI: Closure generates the following warning for this syntax `this.fooMinValue = 10;` _JSC_USED_GLOBAL_THIS: dangerous use of the global this object at line 30 character 0 this.fooMinValue = 10;_. Regardless, I can't use `this` in this case because since the varible is not enclosed in quotes, Closure renames it. Useful (for me) comment, none the less. – Karl Oct 26 '12 at 17:53
  • Hm, I'm not sure what's so dangerous about using the global `this`... Consider this pattern: `(function ( root ){ root['fooMinValue'] = 10; }( this ));` So you capture the global object into the `root` parameter, and then use that parameter to set the global properties. This way, you can still be agnostic about accessing the global object (you don't depend on `window`). – Šime Vidas Oct 26 '12 at 17:59
  • @ŠimeVidas I was checking out the compiler warning and came across this Q [Closure-compiler-warning-dangerous-use-of-the-global-this-object](http://stackoverflow.com/questions/5301373/closure-compiler-warning-dangerous-use-of-the-global-this-object). – Karl Oct 26 '12 at 23:40

3 Answers3

2

Although both are properties of the global object, there is a difference: when you declare the variable with var, its [[Configurable]] internal attribute gets set to false. Therefore, it's not possible to change its attributes with Object.defineProperty (except for [[Value]]). The most notable effect is that such variables cannot be deleted:

​var foo = 'bar';
window['bar'] = 'baz';
console.log(foo); // 'bar'
console.log(bar); // 'baz'
delete foo;       // doesn't work, you can't delete vars
delete bar;       // works, bar is an object property
console.log(foo); // 'bar'
console.log(bar); // ReferenceError

Also, when assigning a variable to a property, you make a COPY of the value instead of referencing the variable. This means external changes to the property don't affect the value of the variable.

(function() {
  var foo = 'bar';
  window['foo2'] = foo; //export foo
  console.log(foo);  // will output 'bar'
  setTimeout(function() { console.log(foo) }, 1000); //will output 'bar'
})();
window['foo2'] = 'baz';
console.log(window['foo2']); // will output 'baz'

The above code will produce the following output:

'bar'
'baz'
'bar'
Chad Killingsworth
  • 14,360
  • 2
  • 34
  • 57
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • "*it's created as a property of the global object (not an actual variable)*" - those two are not mutually exclusive. Global variables are global properties, too. The set of global properties is a super set o the set of global variables. (Your answer implies that global variables are not global properties.) – Šime Vidas Oct 26 '12 at 17:52
  • @ŠimeVidas That was always confusing to me, but [your question](http://stackoverflow.com/q/12692887/825789) helped me clarify. However, I still can't find a way to explain that in simple terms (like one short sentence that would fit this answer). – bfavaretto Oct 26 '12 at 18:09
  • I'll try to put it in one sentence `:)`: A `var` statement in global code (e.g. `var x = 1;`) creates a non-configurable global property, whereas an assignment to a non-existent global property (e.g. `window.x = 1;`) creates a configurable global property. (Both operations create global properties - the difference lays in the `[[Configurable]]` attribute of that property.) – Šime Vidas Oct 26 '12 at 18:54
  • 3
    Also, as it relates to Closure-Compiler, you'll be exporting a copy of the value not a reference to the variable. You'll be able to read the value but external changes won't actually affect the variable value. If this isn't what you intend, you'll need to export these variables as properties on an object. See the `@expose` annotation for details. – Chad Killingsworth Oct 26 '12 at 19:12
  • @ChadKillingsworth Good to know, maybe you should add an answer. I have no experience with the Closure-Compiler, so I can't comment on that. – bfavaretto Oct 26 '12 at 19:31
  • @ŠimeVidas Oh, the subtle details are very interesting. So, what happens if I do this: `var fooMinValue = 10;` then `window['fooMinValue'] = fooMinValue;` as is suggested in the article I site in original post? I'll guess that memory is allocated for both a property and a variable which is certainly not the intent. Is that correct? – Karl Oct 26 '12 at 19:53
  • @ChadKillingsworth. Closure minifies this code `window['fooMinValue'] = 10;` to this `window.fooMinValue=10;`. Which, if I understand you correctly is _exactly_ the same as if I had used this syntax: `var fooMinValue = 10;`? (Therefore, new values can be assinged to `fooMinValue`.) – Karl Oct 26 '12 at 20:46
  • 3
    @Karl I don't know how Closure Compiler interprets that sequence, but I can tell you how it is evaluated in the browser. So, `var fooMinValue = 10;` creates a `"fooMinValue"` global property. Now, `window['fooMinValue'] = fooMinValue;` assigns the value of that property to that same property. Therefore, it's a no-op. (It's not necessarily a no-op, since that property could've been a getter/setter, in which case the getter/setter function might have side-effects.) – Šime Vidas Oct 26 '12 at 20:50
  • 1
    @Karl Yes - if you create it as a property you will be working with a reference and updates go in both directions. Just make sure you reference it consistently (as a property on the `window` object and not as a global variable). – Chad Killingsworth Oct 26 '12 at 20:57
1

It is the same except that if your script is not running on a browser it is very probable that window will be undefined.

You are welcome!

nicoabie
  • 2,684
  • 1
  • 20
  • 19
  • in which case `this['fooMinValue'] = 10` works fine, in general. Or you can pass the global scope into a function like: `~function( window ){ window... }( this );` –  Oct 26 '12 at 17:31
1

It will work; it's perfectly valid syntax; and it's supported in IE6 and up.

Demo: http://ie6test.it/?url=http://jsbin.com/usafeg/2

tuff
  • 4,895
  • 6
  • 26
  • 43