1

I'm trying to up my game, learning and want to adopt a best practice with regards to Namespaces to separate my code from potential overlaps of function names, variables etc. I've come across several mechanisms for implementing this but one thing puzzles me. Many approaches initialize the global Namespace variable like this: var ns1 = ns1 || {};

So this says "if ns1 exists, use it, else create a new variable". But if within that variable, I then create a second function with a duplicate name, it will replace the original. I have a JSFiddle here. The thing that's confusing me is: why use an "or" in the global variable assignation? Since we are trying to separate things out, this doesn't make sense to me. Am I missing something fundamental here ?

Or is it as simple as the possibility that I may have several libraries, so I am re-using my own variable. In which case I should just ensure that "ns1" is actually something much more unique so the likelihood of clashes is reduced? Sorry if this seems a dumb question but I'm just worried I'm missing something and want to do this right. Maybe others in my situation are also confused and this may help. Thanks.

  • This is to give you the possibility to extend your own namespace later, like an addon or enhancements, a new set of functionality that can be incorporated into your existing ns1 namespace or stand alone. like jQuery and jQuery.ui both still use the $ namespace – Pellay Apr 07 '22 at 22:26

2 Answers2

1

var ns1 declares the variable, which always exists. ns1 = ns1 || {} is meant to "initialise the variable with an empty object, unless it already has a value". This is meant to allow running multiple scripts that all use the same namespace in arbitrary order. See also What does "var FOO = FOO || {}" (assign a variable or an empty object to that variable) mean in Javascript? or What benefits to var myObj = myObj || { } when myObj already exists? for details.

Not knowing what modules are getting loaded might not be the best practice, but the pattern has become common and resilience against mistakes is never bad. The primary use case is having a huge application with many modules, some of them optional or lazy-loaded, all using a globally shared namespace for the application. They would then create sub-namespaces (nested objects) for the individual parts within it, not put all their methods on the global namespace.

You don't need to do this when writing a library that will be served as a single file anyway. For library authors, it's a guard against the case where the library (or different versions of it) is accidentally included multiple times.

This pattern is rarely needed in modern web development, where you'd use declarative ES6 modules instead. Each of them comes with its own scope, communication between modules does not happen via the global scope like it did for scripts.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1
var ns1 = ns1 || {};

This means if ns1 exists use it, otherwise set it to a new "clean slate" object.

AKA "use or establish".

Another way to write the same logic would be:

if(typeof ns1 != 'undefined') {
    var ns1 = {};
} else {
    var ns1 = ns1;
}

... but the above is just to show the logic.

So we want to position an app in it's own context (aka namespace) so that all your vars and functions and stuff don't get all mixed up and tangled into the native stuff (and/or other apps).

So this "clean slate" object is "your space" or "your context". And you can build all your stuff into it.

Choosing your namespace name is critical, you should choose a name with a low likelihood for collisions.

This pattern helps when you want to split your app into a number of different files. Since it may become unclear which JS file loads first, ns1 || {} allows any of your app's files to be the one responsible for establishing "your space".

As JS files load, each one will do the same thing to see if "ns1" has already been established... if it hasn't, then go ahead and establish it.

In a web app, running in a web page, the lowest level object available to everything (including default/browser javascript) is "window".

When you write:

var ns1 = "foo"

... you are actually creating a new variable on the window, so it's the same as doing:

window.ns1 = "bob"

So to clarify the "long way" to write ns1 || {} would be:

if( ! window.ns1 ) {
    window.ns1 = {};
}

And the "short way" to do the exact same thing as above is:

window.ns1 = window.ns1 || {}

... and it's intent is to establish "your space" if it hasn't been done so already.

And finally, now that you've establish "your space" or "your namespace", you can then start building it up and add to it like:

window.ns1 = window.ns1 || {}
window.ns1.main = window.ns1.main || {}
window.ns1.main.init = function(){
    //do something   
}
window.ns1.main.someVar = "abc";

And other JS files can add to "main" safely if they use ns1 || {} check/establish as well.

There are many patterns out there for constructing your app, this is just trying to expose the key idea.

bob
  • 7,539
  • 2
  • 46
  • 42