Reputation: 6132
I have the following bit of code:
(function(){
...
var n = n || {};
...
})();
This does what I want, setting n equal to {} since this is the first time it's encountered and will be undefined. Unfortunately, since this inside a function, n
is limited in scope to the function and I can't use it in other scripts.
I wanted to just change the line to n = n || {}
, but I got an error: ReferenceError: n is not defined
Changing it to just n = {}
worked as expected; however, this is not what I want. I don't get why n
's undefinedness causes an error when I don't use var
and works as expected (being a falsey value used to get the right side of the OR statement) when I do. Based on my understanding of the var
keyword, I would expect it to be both or neither.
Why does the var
matter, what is going on here?
Upvotes: 0
Views: 107
Reputation: 26696
1) in the first round of evaluation, var n = n || {};
you're creating the variable:
var n = undefined;
2) in the second round of evaluation, you are setting the value conditionally:
n = undefined || {};
3) without the var statement, you've got a var which doesn't exist anywhere at all, being referenced
var myVar = non_existant_var; // error
If the var already exists, say, in the global scope, or any other function which the current function is nested inside, it will use whatever n
it finds, on the way up the chain. If none exists, it will have a fit.
So rather than intentionally poking holes in your code, trying to get the code to know which scope you're trying to access, why not access it directly?
(function (name) {
window[name] = window[name] || {}; // returns undefined and not reference error
var ns = window[name];
ns.init = function () {};
// .............
/* Don't return the application to a var -- it already exists in the global scope */
}("BigLongApplicationName"));
BigLongApplicationName.init(); // === window.BigLongApplicationName.init();
Upvotes: 0
Reputation: 2558
So it sounds like you're having trouble creating a global variable.
Good.
Creating global variables in JavaScript is easier than it should be.
Your problem is that n
is not defined (duh). You can't reference a variable that's not yet defined. But you're probably thinking, "How is that different from the version using var
???" And that's a good question.
JavaScript does something called "hoisting" of variable definitions. If you define a variable within a function, that definition gets implicitly relocated to the top of the function. So while you wrote:
var n = n || {};
What really happened was closer to:
var n;
n = n || {};
However, it's not really that simple, because if you tried to write that code, you'd wind up with n
always being set to {}
. But the general essence is there. The variable declaration happens before the assignment.
If you remove the var
, it will cause a reference error because there's no declaration to hoist anymore. So one "proper" (and I use that term loosely, because it's never "proper" to create a global variable) way to do what you want is to take your var
and place it outside your function wrapper. Like so:
var n = n || {};
(function () {
//do stuff.
}());
Unfortunately, you can't do it like this:
var n;
(function () {
n = n || {};
}());
That has the same "problem" as my example above. If n
is defined elsewhere, it will be set to undefined
by the var n;
and then set to {}
in the function. By doing the whole declaration and assignment outside the function, you get what you're looking for. Which I assume (based on the title of your question) is actually namespacing and not some arbitrary global variable. That would be naughty! ;-)
UPDATE:
Oh, and by the way, a better way to do this might be by explicitly referencing the global object:
(function (exports) {
exports.n = exports.n || {};
}(this));
This will probably play better with things like node.js and anything that might wrap your code (like a $(function() { })
).
Upvotes: 3
Reputation: 7295
1) Small change would help:
(function() {
var n = window.n = window.n || {};
// Code of your module...
n.hello = function() {
alert('Hello');
};
})();
n.hello();
DEMO
In this way you have n
, visible globally and a local reference n
to the same object
inside your function.
2) I'm suggesting also you to redesign it in next way.
Make each module like:
var MyApplication = (function(app) {
// Code of the module here...
app.hello = function() {
console.log('Hello!');
};
return app;
})(MyApplication || {});
MyApplication.hello();
Upvotes: 1
Reputation: 46657
You've encountered the difference between an undefined variable and a defined variable with an undefined value.
Referencing an undefined variable will cause an exception (ReferenceError: n is not defined
)
Referencing a defined variable with an undefined value is fine and will cast to false
in a condition.
To avoid this, you can reference n
as a property of the window
object, as a property can never be undefined, only have an undefined value.
(function(){
...
window.n = window.n || {};
...
})();
Upvotes: 2
Reputation: 298326
n
has not been declared yet, so checking whether n
is true-like won't work. You can check explicitly to see if n
has been declared yet:
n = typeof n !== 'undefined' ? n : {};
But that isn't very nice to look at. To place something in the global scope, use window.n
in place of n
or declare n
outside of your function:
var n;
(function(){
...
n = n || {};
...
})();
Upvotes: 1
Reputation: 12711
var
creates local variable while not using it pollutes global namespace. Browsers should prevent this as mostly you don't want to create a global variable.
What you can do is using window
object:
window.n = window.n || {}
But this will work only in browser environment. If it's not the case (eg. you're using serverside JavaScript) then retrieve the global object this way:
var global = (function getGlobal(){
return (function(){
return this;
}).call(null);
}());
and then:
global.n = global.n || {};
Upvotes: 0
Reputation: 143169
You can add var n;
before your code and you will have global n
. var
matters because it makes n
local to the function.
Upvotes: 0
Reputation: 179136
With strict mode you need to explicitly use the global namespace, which is typically window
; changing the line to use window.n
should get you what you want:
window.n = window.n || {};
Upvotes: 0
Reputation: 624
At the end of the function do:
window.n = n;
That will place n in the global namespace allowing you to use it in other scripts.
Upvotes: 0