9

I have a fairly good grasp of the concepts of scope and closures in JavaScript.

Moreover, the following sites provide examples of how JavaScript namespaces can be implemented:

  1. Everything you wanted to know about JavaScript scope
  2. Namespacing in JavaScript

What I still do not understand is how many people seem to mix the concepts of scope and namespace. Furthermore, the same people often also mention how one should not "pollute the global namespace" and not "create global variables / variables in the global scope".

Questions

  • Is it not correct that scope and namespace are two completely different concepts?
    • Namespace: Grouping of code such that names within the group are unique and cannot collide with similar names in other namespaces
    • Scope: Defines the accessibility of variables. JavaScript has two scopes, global and local/function scope (ES 2015 introduced block scope with let/const)
  • Is it correct that the following object literal creates a new namespace for bar, avoiding to pollute the global namespace (except for foo), but that bar is still in the global scope: var foo = { bar: 42 }
  • Is it not wrong to say "don't create global variables so you do not pollute the global namespace"? Global vs local variables (scope) is different from namespacing. As seen, it is perfectly possible to shield a variable in a new namespace, and still have it be in the global scope.
  • If avoiding to pollute the global namespace is the only reason for why we should not create global variables, is it not enough to just create new namespaces and still keep it all global?
Magnus
  • 6,791
  • 8
  • 53
  • 84

1 Answers1

1

Is it not correct that scope and namespace are two completely different concepts?

I would not say that scopes and namespaces are completely unrelated. If we take the literal meaning of "namespace", it's a space of distinct names - unique and not colliding with names from other spaces, as you say.

A scope definitely forms a name space in that regard - the variable names are distinct and don't collide with names from other scopes. However, a scope is internal and can't be accessed from outside, so it's not particularly interesting for organising things.

An object also forms a name space - the property names are distinct and don't collide with names on other objects. This is why objects are used for structuring code into modules, and this is the traditional meaning of "namespace" in JavaScript.

Is it correct that the following object literal creates a new namespace for bar, avoiding to pollute the global namespace (except for foo), but that bar is still in the global scope: var foo = { bar: 42 }

No, bar is not a member of the global scope. It's a property of some object.

Is it not wrong to say "don't create global variables so you do not pollute the global namespace"? Global vs local variables (scope) is different from namespacing.

Globals are a bit special in JS: they are both properties of the global object and variables in the global scope. That's why we talk of "the global namespace" to encompass all - and specifically to emphasise that the names must not collide.

If avoiding to pollute the global namespace is the only reason for why we should not create global variables, is it not enough to just create new namespaces and still keep it all global?

Creating namespaces, like {bar: 42} in your example above, does still create global variables: foo. It just creates fewer variables - one per module. Also it creates a certain naming convention, namely that global variables should refer to modules and not to mundane variables. We wouldn't use var i, increment, decrement; but var counter = {i: …, increment(){…}, decrement(){…}};, and refer to the purpose of them in the name counter.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thank you, Bergi. Could you please elaborate on the point of `bar` not being in the global scope? To my understanding `bar` is a property of `foo`, which in turn is a property of the global object (`window` in browsers). Thus, since `bar` is not in a function scope, it must be in the global scope. Side note: We had the option to define `bar` outside the new namespace (`var bar = 42`), in which case it would be in both the global namespace and the global scope. Instead we put it in its own namespace (object) to avoid name collisions. It is not in a function though, so no new scope was created. – Magnus Apr 30 '18 at 13:27
  • @Magnus `bar` is not in any *scope* at all, it's an object property not a variable. That's why it is not in the global scope. – Bergi Apr 30 '18 at 13:33
  • @Magnus We could imagine a "name space" consisting of all globally accessible paths (similar to how the URI namespace is a superset of the domain namespace). "`foo`" and "`foo.bar`" would then be in that namespace. But it's not what we usually mean by the term "global namespace". – Bergi Apr 30 '18 at 13:36
  • Hmmm, I see. But, `bar` kind of works that same way as a variable right? After all, we were deciding between `var bar = 42` or namespacing it inside an object (thus making it an object property). Is that the right understanding? Additionally, is `foo` not both a variable and also a property of the global object? – Magnus Apr 30 '18 at 13:39
  • Another follow-up, if I may: If the issue is creating name collisions, then the statement should not be `Don't create variables in the global scope`. Yes, as you say a side effect of creating local variables is that they are namespaced, but that is just a side effect. The statement should instead be: `Don't create variables in the global *namespace*`. It is more specific / less misleading, would you not agree? – Magnus Apr 30 '18 at 13:44
  • Lastly, what about garbage collection? Is that not a reason for creating variables in local scopes? So, in summary: 1) Create variables in new namespaces to avoid name collisions. 2) Create variables in local scope to ensure they are garbage collected when the scope looses focus. – Magnus Apr 30 '18 at 13:46
  • @Magnus It doesn't really matter whether `bar` is a variable or property, the point is that we put it in a local namespace (of either scope or object kind) that is not the global one. (Still, properties work quite different than variables, and you need to use the appropriate tool for the job). Yes, globals that are both variable and property are weird. – Bergi Apr 30 '18 at 13:54
  • @Magnus I don't think this has anything to do with garbage collection. We can keep scopes alive with closures, and we can collect objects by no longer referencing them. – Bergi Apr 30 '18 at 13:55
  • Understood. The following post kind of has a valid point on garbage collection no? https://stackoverflow.com/questions/8862665/what-does-it-mean-global-namespace-would-be-polluted . Can't be great practice to keep the memory full of primitives/objects that are no longer used. – Magnus Apr 30 '18 at 14:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/170091/discussion-between-magnus-and-bergi). – Magnus Apr 30 '18 at 14:05