1

According to this article

http://www.mediaevent.de/javascript/globale-lokale-variablen.html

Global variables are in JS pretty dangerous.

I'm sorry that it's in German, but I'm gonna point out out the 2 main statements of the article.

The first is already in the 2nd paragraph of the head statement.

It says something like "In JS global var's are dangerous as they can get accessed by other scripts over the name" That's fine so far, as that's mostly the way why I want to use global var's don't I?

But in the article it sounds as this could happen randomly. and that's for sure not the expected behaving, is it?

But what is much more frightening me is the second last sentence. It forecasts that memory leaks will generated if a function that declares a global variable is called multiple times. But how could this happen if the name is still the same? how there can be multiple vars declared global with the same name? Or is this article probably written by some one just "half-knowledge"? Or maybe just addressed to some one who isn't used to the difference between global and local at all? Or is JS really behaving in this way?

Now a concrete example:

I want some one who logs in to my page to create a Random generated token and submit it by clicking login. on each other button I want that this token is accessed by a different function and just submit it, so that just for a new login the key will be regenerated.

For that key I was thinking about using a global variable, which gets declared by one function and gets returned by another. But as I will generate/regenerate the key possibly more then once, would this generate memory leaks? Or is this article I'm referring to probably just dramatizing? If this is really the way JS is behaving, what would be a good way to make a variable accessable from different functions in my case?

mplungjan
  • 169,008
  • 28
  • 173
  • 236
dhein
  • 6,431
  • 4
  • 42
  • 74
  • 2
    Globals are fine, but kept to a minimum. Create a namespace and put everything in there. I don't read German but I guess the problem with globals is when you forget `var` you declare an implicit global that can cause very nasty bugs. – elclanrs Oct 11 '13 at 08:10
  • yeah that was a point of the article I agreed with. but the article is saying flobals are dangerous at all. – dhein Oct 11 '13 at 08:11
  • It's dangerous to have tokens 'generated' client-side, as they can pass whatever they want. – ps2goat Oct 11 '13 at 08:11
  • @ps2goat thats true, but I will hash on serverside the ip into this token. and even if he gets this token the only think someone could archive withit would be forceing some one to relogin, ou can't get a new token that gets accepted without verifying it to the server by login + password. So I see there no securtity issue on generating the token on client side. – dhein Oct 11 '13 at 08:15
  • 1
    I don't know your logic, but keep in mind that several machines can have the same IP address. – ps2goat Oct 11 '13 at 08:19
  • @ps2goat well thats a point, but thats any way to be changed later, for my current state the client side would be enough. But back to my problem. Would there even be another way to acces a variable staticly from 2 independend functions wihtout declaing the var global? – dhein Oct 11 '13 at 08:22
  • any variable outside a function can be accessed by any script loaded on the page, provided the script with the variable was loaded prior to the others trying to hijack the variable. – ps2goat Oct 11 '13 at 08:24
  • So yes, a script can access a variable declared on another script file. – ps2goat Oct 11 '13 at 08:24
  • You absolutly missed my question, My question was "Is there another way to acces a variable from outside a function WITHOUT the variable is declared as a global variable?" – dhein Oct 11 '13 at 08:29
  • If it is not declared outside of a function, then no. My previous answer is still valid as you do not have to explicitly call a var global, as @elclanrs mentioned, for a var to be global. – ps2goat Oct 11 '13 at 08:31
  • now I'm confused. But I guess at least I got now that the article is dramatiazing. – dhein Oct 11 '13 at 08:45
  • @Zaibis Regarding *"Is there another way to acces a variable from outside a function WITHOUT the variable is declared as a global variable?"*, you might be interested by [this related question](http://stackoverflow.com/questions/11192875/is-it-possible-to-gain-access-to-the-closure-of-a-function). Regarding leaks in js applications : when you have one (which rarely happens if you code correctly) you may fix it. Leaks aren't something that "just happen". – Denys Séguret Oct 11 '13 at 08:55

3 Answers3

9

The problem with globals is not memory, and it's not performance.

The problems with globals is entirely different. The problems are that they introduce global state and that scripts are not bound to a namespace.

Let's go through these problems one by one.

Having global state

This is the biggest issue here. Coding necessitates that the dependencies of a module be explicit and that communication between pieces of code is very clear.

When you have global variables which part of the code uses the variable is not nearly as clear and you can't be sure what part of the code needs it and what does not.

Let's say I have a Zoo project and I have a Bathe service that cleans an animal. Instead of passing Bathe around to each animal that needs it I have it on a global namespace and I just call Bathe(myAnimal).

Now I want to restructure my zoo and I want to know which animals need bathing because I want to optimize that. I have no way of knowing that other than going through my whole code. In order to see if my Giraffe needs bathing I have to read the entire code of the Giraffe class. If instead I passed Bathe to the constructor of Giraffe instead of using it or creating it inside giraffe (a concept called dependency injection) I can see that a Giraffe needs bathing just by reading the signature.

Now this can get way worse, what if I have state? If I'm actually changing a global variable in multiple places it becomes extremely hard to track. In a more than a few lines code base this means that you have state changing all around and no clear indication of who is changing it.

This is the main reason you should avoid globals altogether .

Scripts are not bound to a namespace

If I have two scripts on a page and my first script declares a A variable on the global namespace, the second script can access that variable. This is useful because scripts can interact this way but it's very harmful because it means that scripts can override each other's code, and communicate in an unclear way.

This of course is completely mitigated if you use a module loader like browserify or RequireJS which means your whole script only exposes two globals - require and define and then script loading is done through the loader.

This way the way independent pieces of code interact is well defined. That doesn't prevent you from creating variables on the global object, but it helps mitigating the need to do so in a uniform manner.

A note on security

Of course, anything on the client side is compromised, you can't do security or anything like that in client side JavaScript on an insecure browser (that is, you didn't prevent anything external on) because the client can just run arbitrary code on your code and read it.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • Ok I don't udnerstand it at all, but sounds also fine to me :) To the security issue: When a client is fiddeling this token, I will notify on my server the missmatch of IP and token and force to relogin. So the content is bound to the IP and the token just verifys your IP. My view is: Even if you fiddle the token, you just log out your self. In view of the other side, multiple users have same IP. Then it is the problem of that IP's network administration if their users try to hack each others account on my page as they are harming each other internally. Isn't this a arguable point of view? – dhein Oct 11 '13 at 08:58
  • @Zaibis "I don't understand at all" - which parts? I can provide relevant code samples if that helps. As for security, it's perfectly OK to challenge the server but you can't store the credentials on the client in JavaScript - See http://programmers.stackexchange.com/q/200790/56971 – Benjamin Gruenbaum Oct 11 '13 at 09:02
  • Nah its just the vocabular you used I'm partial nto used to. But nevermind. As I said, I wont store a password in JS. the way it runs is expected like this: User enters his ID + password. a HTML form submits this info + the on submit generated token. serverside acepts the login, checks the id + pw for correctness, and if it is amtching the server autheticates the id to be valid from this ip as far on each request the token will match the authentication token to the id AND the ip didn't change. This should aware of unauthorized acces. shouldnt it? – dhein Oct 11 '13 at 09:22
  • @Zaibis Yeah, that makes sense. As long as you validate requests on the server you're good. – Benjamin Gruenbaum Oct 11 '13 at 09:24
  • "scripts are not bound to a namespace" (@Benjamin) - Bzzzt - wrong. This namespace is called `window`. – Thevs Oct 11 '13 at 17:45
  • @Thevs you misread what I wrote. In "Scripts are not bound to a namespace" I mean _different_ scripts are not bound to _different_ namespaces. That is, unlike different languages, when you use a script tag to include a script, let's say libA, it gets access to the global namespace and can pollute it, rather than everything libA outputs being on `var libA = require(libA)` without it getting access to the "global scope". – Benjamin Gruenbaum Oct 11 '13 at 18:08
  • 1
    @Thevs Also, `window` is not a namespace. It's a host environment object containing things and giving access to the global scope when running JavaScript in the browser. The language itself has _nothing_ to do with `window`. and the best indication for this is that other environments like NodeJS contain no window object. – Benjamin Gruenbaum Oct 11 '13 at 18:10
  • Is it insecure to store user data on a window variable? As an example, would doing `window.userPasswords=["pass1", "myPass2", ..etc]` expose those passwords to all clients? – tnrich Dec 11 '18 at 19:44
6

There are three big problems with global variables:

  1. name collisions
  2. code complexity
  3. garbage collection

Name collision

The problem with having variables in global scope is that you have less control over what else is in that scope. Your code uses a ga_ variable globally and works fine, but when you add a Google Analytics snippet that uses the same variable things unexpectedly fail and it can be quite hard to see why your shopping cart fails 2 out of 3 page loads.

If you can wrap your code in an IIFE to prevent having any variables in global scope, you should do that. Obviously there are cases where you actually want to have your code accessible globally (ex: jQuery library). In those cases, it is best practice to keep all your stuff in a single namespace (jQuery) with a relevant name.

Code complexity

It is usually a good idea to partition your code so that individual pieces have minimal interactions with each other. The more pieces interact the harder it is to make changes and to track down where bugs come from. Obviously a global variable can be accessed anywhere so when you have a problem with some code that accesses a global variable, you have to inspect every usage of that variable which can be quite a big pain. The thing to do to avoid these pains is to keep variables as local as they can be and encapsulate pieces of code so they can't interact with each other except through specific interfaces.

Memory leaks

In JavaScript you have little control over the garbage collection process. All that is guaranteed is that if you can access a variable it will not be garbage collected. This means that if you want something to be garbage collected, then you must make sure you can't access it anymore. While a global i variable which keeps a number won't be a big deal, as @Boluc Papuaccoglu mentioned when your global variable keeps more and more properties over time (an array of XHR requests for example, or array of created DOM objects), the memory consumption turn into a big deal.

All of these situations are worst case scenarios and you probably won't have issues with a small application. These recomendations have most value when you're starting to learn programming because they develop good habits and when you're working on complex applications when they save you time and money wasted on debug or difficult to do improvements.

Tibos
  • 27,507
  • 4
  • 50
  • 64
  • Why would a person keep an array of XHR requests or DOM objects that he doesn't actually need? – John Dvorak Oct 11 '13 at 09:05
  • You can have a real example of memory leaks from the Google Closure Library dealing with events. They had a global object keeping track of event listeners and specific components used that object to register their listeners. With complex logic, components failed to unlisten for some events resulting in memory leaks. The solution they chose was to give up on the global array and have each component keep a local array of event listeners. As i said, in a small app you won't have problems, but with complex apps it's not as easy to keep track of everything. – Tibos Oct 11 '13 at 09:14
  • 1
    it would be nice to point to the details of this bug from the question – John Dvorak Oct 11 '13 at 09:15
  • Well I'm not learning to programm, I'm already a professional C coder, but never had to use JS before. But lets simplyfiy my question you talked about namespaces: Is there a way in js to declare a var as static? for example I have 2 functions 1 is "generate token" which is generating the token and calls settoken(token, 1) where 1 as param means I want to set the variable and when I want to request the token: then I do settoken(0,0) which returns the token. so it would be already fine for me if there would be in function scope a var, whichs life time isn't constricted to the functions scope. – dhein Oct 11 '13 at 09:31
  • You have 3 things in the global scope: 2 functions and 1 variable. The best thing to do is to wrap it in an IIFE to keep the variable private and expose the two functions: `var Token = function(){ var token; return { generate : function() { /* sets token above */}, get : function() { /* gets token above */ } } }();`. You now have a global Token object (namespace) which exposes the two functionalities you are looking for: generate and get. The less the code that uses it knows about the implementation, the better. – Tibos Oct 11 '13 at 09:41
  • Nice answer +1 , underlines some of the other points I did not address in mine. – Benjamin Gruenbaum Oct 11 '13 at 09:42
  • @Tibos I really try to get your sample code, but I don't understand its fucntionallity, and even in function scope it won't remember the next time i call the outer function what the inner token was. or am I wrong? I really try to understand :/ E: ah w8, wiki explained me get and set. but why the function will remember the value of th set when i want to get? as it life time is jsut function scope, isn't it? – dhein Oct 11 '13 at 11:03
  • Or are in JS all variables "static" so that they never get undeclared just because I finished their scope? In C I cant refer to a object when its "local" and Im not in any instance of its scope. So in JS is there a difference? would `function foo(){var v = 5}`theoretically be accesiable from outside? or would it be indetermined? – dhein Oct 11 '13 at 11:10
  • @Zaibis no, it can not be accessed from the outside. Once the function is done executing `v` loses its last reference and the GC can safely deallocate that memory. – Benjamin Gruenbaum Oct 11 '13 at 13:08
  • @Zaibis The code for the get function should be `get:function() {return token; }`. You don't declare `token` in `get`'s scope so it will access the `token` variable declared in the outer function. Nobody else but the `get` and `generate` functions can access it because `token` is not defined in the global scope, making it much less prone to errors. – Tibos Oct 11 '13 at 13:26
  • My problame isn't the accesibility I'm asking for life time! I want to know will v, or in you example `token` keep its value between the call to generate and the get toke calls. or will it be indetermined? – dhein Oct 11 '13 at 17:40
  • token will keep its value in this example. It is kept alive by the get and generate functions (and will therefore keep its value). As i said before, if a variable is accessible it will not be garbage collected. – Tibos Oct 14 '13 at 07:36
0

Regarding memory leaks: Let's say you have a function, and within it you define a var, and use it for some purpose then return from the function. In this case, the memory used by the variable will be freed. However, if you relied on a global variable to do the same thing, then the memory would continue to be allocated long after your function exited. Extending the same scenario, imagine that your function adds properties to this variable with names that depend on the data the function is processing (like Order ID, Customer Name, etc.) Now, each time your function gets called, more and more properties will be appended to this variable and it will grow and grow.

Boluc Papuccuoglu
  • 2,318
  • 1
  • 14
  • 24
  • Thats what I understand under a global variable. But refering to the article exactly this usage is forcasted to have dangerous sideeffects. – dhein Oct 11 '13 at 08:16
  • and regarding to your edit: Ofcourse it will grow, but thats not a problem caused by global variables this problem is caused by a ucoder who doesn't know how to manage his memory, isn't it? – dhein Oct 11 '13 at 08:17
  • Regarding the growth, if the variable was declared as a function scope, it would not be necessary to "clean up". If you are using a global variable, you have to free memory before exiting the function. Also, there are features to JavaScript like closures which create variables that are protected from being accessed outside of the function. – Boluc Papuccuoglu Oct 11 '13 at 08:24