1

Why does this function run and not initialize global XYZ with the return value?

"use strict";
XYZ = (function(){
    var obj = {'a':1,'b':2,'c':3};
    console.log("about to return:");
    console.log(obj);
    return obj;
    })();
 console.log(XYZ); // shows undefined

jsfiddle

What seems odd is that the first two console.log return sensible output, and then Chrome throws Uncaught ReferenceError: XYZ is not defined

When using window.XYZ explicitly, this works fine:

"use strict";
window.XYZ = (function(){
    var obj = {'a':1,'b':2,'c':3};
    console.log("about to return:");
    console.log(obj);
    return obj;
    })();
 console.log(XYZ); // shows a:1, b:2, c:3
Paul
  • 26,170
  • 12
  • 85
  • 119

1 Answers1

1

Either will work if "use strict;" is removed. But don't do that -- keep reading.

Strict mode prevents XYZ = ... from becoming a new global variable.

John Resig explains in his overview of strict mode:

An attempt to assign foo = "bar"; where foo hasn’t been defined will fail. Previously it would assign the value to the foo property of the global object (e.g. window.foo), now it just throws an exception. This is definitely going to catch some annoying bugs.

The code with window.XYZ = IIFE() works in strict mode because here the assignment is to a property of an existing object, window.

Using window.XYZ might be "good enough" for many applications, but you may encounter a platform (such as Meteor) where using window.XYZ "short circuits" dependency management in the package manager. In such a case, strict mode can be enabed inside the IIFE but not at the page level.

To use strict mode with a singleton IIFE assigned to a new global, only turn on strict mode inside the IIFE on its first line.

XYZ = (function() {
  "use strict";
  var obj = {
    'a': 1,
    'b': 2,
    'c': 3
  };
  console.log("about to return:");
  console.log(obj);
  return obj;
})();
console.log(XYZ);

Warning: "use strict;" as the 2nd line does not enable strict mode:

Don't do this:

XYZ = 0;
"use strict";
XYZ = ...

You can test whether strict mode is enabled by looking at this inside a function where this is not explicitly set. When strict mode is true, this will be null when unset, but when strict mode is false, this will be window.

See also: What does "use strict" do in JavaScript, and what is the reasoning behind it?

Community
  • 1
  • 1
Paul
  • 26,170
  • 12
  • 85
  • 119
  • Putting `var` before `XYZ` solves the problem, you can add this in answer. Updated [fiddle](http://jsfiddle.net/tusharj/wr08jrh2/1/) :) – Tushar Oct 05 '15 at 04:48
  • `var XYZ` is not global. This is for library code that is defined in one js file to run in other js files. – Paul Oct 05 '15 at 04:50
  • An option could be, setting the value in global scope from inside the IIFE, `window.xyz = obj;` and not returning anything. Then you can remove `XYZ = `. The error will be solved. – Tushar Oct 05 '15 at 04:51
  • Yes, but MeteorJS, which is one of the consumers of this code, discourages use of `window` to create globals in modules, because this messes up their code-modifying dependency handling is `package.use()`. The fact that `window.XYZ` works is mentioned in the quesiton. – Paul Oct 05 '15 at 04:57