What is the sanest way to use global variables in Javascript? - javascript

What is the best way to use global variables in Javascript?
Should I do document.x="this", document.y="that"?
How will I avoid collisions in the long run?

I personally define a namespace for my application data
var myns = {};
and define everything inside that namespace
myns.foo = 50;
In this sense, the only variable you attach to the global object is the namespace object. Everything else is globally accessible, but within your namespace. This reduces collisions on the global object, and eventually you can define a different namespace if you so wish.

IMHO, the best way to avoid collisions is to work on a temporary scope, using a self-executing function expression, keeping all your library code encapsulated, and expose your global objects in a very selective way, using as few as possible:
(function(){
var myLib = window.myLib = function(){ // expose object
// Initialize
};
// ...
})();

Anything declared outside a function, is, by default, global. You don't need to attach it to document explicitly to make it so. In the long run you WONT avoid collisions which is why this is a Bad Practice.
You can write Object Oriented JS and keep your variables in one name space, more or less.

As other answers point out, placing your code inside a function prevents it from being globally accessible. You can also use the return value of the function to expose only the variables you want:
var myAPI = (function() {
var examplePrivateVariable = 1;
var examplePublicVariable = 1;
function doSomethingPublic() { /*...*/ }
function doSomethingPrivate() { /*...*/ }
return {
examplePrivateVariable: examplePrivateVariable,
doSomethingPublic: doSomethingPublic
};
})();
myAPI.doSomethingPublic();

I agree with the comments above. I typically create an object, hide the data, and expose getters (rarely) and behavior as needed.

Related

Passing a window object into Javascript namespace

I'm trying to better understand namespacing in javascript and found an example of a javascript Immediately-invoked Function Expression that is taking the window object as a parameter. Here is the code from it:
var CG = CG || {};
CG.main = (function(window) {
var FOCAL_LENGTH = 8.0;
var context, width, height, startTime;
var init = function() {
var element = document.getElementById("canvas1");
context = element.getContext("2d");
width = element.width;
height = element.height;
startTime = (new Date()).getTime() / 1000.0;
tick();
}
var original_onload = window.onload || function() {};
window.onload = function() {
original_onload();
CG.main.init();
}
return {
init: init,
draw: draw_shape,
clear: clear_canvas
};
}(window));
At the end of the namespace definition, there is a line with window in parenthesis which I am confused as to the functionality of. I think that the purpose of adding the parameter of window to the end of the definition is to bind the global window variable to the namespace which will then add different properties to the window, but I can't really be sure.
In another example there is a random variable name passed into the definition of a namespace, and at the end of the namespace definition, the actual name of the namespace is passed as a parameter:
var namespace = namespace || {};
// here a namespace object is passed as a function
// parameter, where we assign public methods and
// properties to it
(function( o ){
o.foo = "foo";
o.bar = function(){
return "bar";
};
})(namespace);
console.log(namespace);
So there are really a couple of questions here:
What is the functionality of passing a parameter at the end of the namespace definition?
If my intuition for how this all works is incorrect, what is the general structure for this kind of namespace creation javascript?
Clearly I'm very new to this so any help would be appreciated, thanks.
I will try to explain this as well as I can but my understanding of it comes from Kyle Simpson. He's awesome, you should look him up. :-D
You are asking a question about immediately invoked function expressions (IIFE), passing arguments to them, and why someone would do that.
First, the reason IIFEs are being used in this context is to restrict the scope of variables.
This is important because as programs become larger and many pieces are added on you can easily have conflicts from one variable to another.
app.js could have
variable = "thing";
and shortly after somethingelse.js could have
variable = "not thing";
That is a huge problem. It is avoided in javascript by creating "modules" or functions that immediately run and run once.
That way, the variables and methods you create in your function don't "pollute the global scope/namespace."
BUT, what if you NEEDED or WANTED something to be available on the global window object?
Well, you could do that by adding it to the "window" which is the global scope in javascript.
(function Module(window){
var _thing = "private thing that only exists in this function";
window.thing = _thing;
//IS NOW AVAILABLE GLOBALLY AND EXPLICITLY ON WINDOW OBJECT
//window.onload you can wait for DOM/page before running the rest
})(window);
You also could have named it anything you wanted inside your function:
(function niftyModule(global){
global.variable = "nifty text!";
})(window)
This becomes especially important when you are using multiple libraries.
For some reason, everyone likes to use "$" as the representation of their library so you can access their private methods (which are really just functions inside an IIFE too! (its a really popular way to build good stuff).
So, what if you are using jQuery and 2 other libraries that also use $ to access their public methods/api??
Easy, you can assign which one you want to assign what variable inside your function/module scope by passing it in as an argument!
(function NiftyModule(window, $){
//Now, every time you use $ in here it means jQuery and not something else!
})(window, jQuery);
It is important to play around with functions and scope. Build some variables in different ways.
For example, is....
var text = "nifty text";
the same as
text = "nifty text";
How about if you do the same thing inside functions? How do those two versions differ?
Also, get used to building your own programs in IIFEs and properly restricting the scope of the code you are writing.
You can also return objects from functions which have the methods and variables you want to access globally on them without adding them to the window object.
It is complicated at first but in the future it saves you a lot of trouble and bugs!
Finally, In your example of:
//initialize a global variable called namespace. If this already
//existed then assign it the previous values. If not, make it an empty
//object.
var namespace = namespace || {};
//pass namespace into an IIFE. Within the IIFE refer to namespace as "o"
(function( o ){
//assign a variable to namespace
o.foo = "foo";
//assign a method to namespace
o.bar = function(){
return "bar";
};
})(namespace);
//now when you log namespace it will have those properties.
console.log(namespace);

Tune My Javascript

I have a JavaScript global Array, which I'm using in multiple functions. I heard that using global variables will give some performance headache. So, can anyone suggest me how I can avoid using global variable in this case?
var tpaArray = new Array();
In multiple functions, I am using and popping value from it.
[Note] In my code I am actually using multiple global variable and arrays
Global variables are not a performance problem. The problem with globals is that the global namespace is already very, very crowded, and so dumping your symbols there leads to the possibility of conflicting with something else.
It's almost always possible to avoid having globals. The usual way is to wrap all of your code in a scoping function:
(function() {
// Your code here
})();
Then you can have nested functions inside that function, and "globals" within that function that they all share.
(function() {
var someVar;
function foo() {
// You can use `someVar` here
}
function bar() {
// And also here
}
foo();
})();
That said, it's best to avoid having lots of shared variables or near globals, as it makes for writing functions with side-effects, which can be difficult to maintain.
If you have lots of variables, you can put them all into an object and pass this as an argument to each function. Then instead of accessing tpaArray, you'd access data.tpaArray, where data is the name of the argument.

Advanced Javascript initialisation

I'm having trouble deciphering the following Javascript initialisation statement:
(function(NAMESPACE) {
NAMESPACE.nav = {};
var nav = NAMESPACE.nav,
_init = false,
_isNavOpen = false,
_inner = document.getElementById('inner-wrap');
// constants
nav.CLASS = 'js-nav-open';
nav.CLASS_READY = 'js-nav';
nav.CONTAINER = '#nav';
nav.DURATION = 400;
nav.HAS_CSSTRANSITIONS = $('html').hasClass('csstransitions') && $('html').hasClass('csstransforms3d');
...
...
// toggle open/close
nav.toggle = function(event) {
event.stopPropagation();
if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
nav.close();
} else {
nav.open();
}
// this is for the links
if(event) {
event.preventDefault();
}
};
}(PROJECT_NAME));
It seems unnecessarily complicated - calling (or setting?) 'nav' 3 times in 2 lines. Can somebody please explain what the point is of flipping it around like this?
This is an example of a JavaScript closure which is commonly used to create private scope and avoid having the objects pollute the global scope.
It is very common to create plugins this way to avoid conflicts with other functionality on the page as a result of variables with the same name etc. Essentially it's a mechanism for managing scope.
This is a common practice when using jQuery:
(function ($) {
var div = $('#my-div');
// Etc
}(jQuery));
Wrapping your script in a closure ensures that certain variables will have the values you expect them to.
For example, jQuery uses the $ for doing just about everything. Most people like to use $('do something') rather than jQuery('do something').
But say that you have another library on the page that also uses the global variable $.
By wrapping your code in the closure, you "reserve" the $ as jQuery's, and jQuery's alone. (When you pass in jQuery as the argument to closure, $ can only mean "jQuery," in the scope of this function.)
Similarly, in your example, you are reserving the NAMESPACE variable. Even if there were another variable called NAMESPACE, causing a racket somewhere else on the page, by passing in a variable at the end of your closure, you will be guaranteed that NAMESPACE will be the object you expect it to be (at least within the closure).
Say that you had a global variable called AbominableSnowman, but you wanted to use AS as a shortcut. By doing this:
var AS = "Apple Soup";
(function (AS) {
AS.tellMeAboutSnowmen();
alert(AS.snowballs);
}(AbominableSnowman));
Your code will still function as you intended. (Proof: http://jsfiddle.net/RUzZH/1/)
As for "flipping it around," it seems like the original programmer wanted to shorten NAMESPACE.nav down to nav. This was probably the best way of doing that.
An alternative (not recommended):
// It's best to limit your assignments to 1-per-line
// This kind of code isn't fun to debug, or even read
var nav = NAMESPACE.nav = {};
It doesn't seem like something worth fretting over. However, since this script interacts with NAMESPACE.nav quite often, it will be slightly, slightly faster to directly reference the .nav property with the nav variable. (This really is a micro-optimization, but in this case it's conveniently justifiable for a different reason [sake of clarity].)
Here's a line-by-line explanation (with headers just to break it up):
Setup:
// Create an anonymous function expression taking `NAMESPACE` as a parameter.
// Likely the *real* namespace will be passed to the function at the end
// with ... })(realnamespacetomodify);
(function(NAMESPACE) {
// Create the new part of the namespace. Note that we are editing a reference
// so really this change happens on whatever object was passed in.
NAMESPACE.nav = {};
// Create a local pointing to this new sub-namespace. Probably just for
// convenience, also possibly for portability (if the name is used in closures,
// then those closures don't need to refer to NAMESPACE directly).
var nav = NAMESPACE.nav,
Module definition:
// While nav refers to an object likely in global scope, nav itself can
// never be referred to from global scope because it is a local here.
// These variables are local here. They can never be referred to by global scope.
_isNavOpen = false,
_inner = document.getElementById('inner-wrap');
// These variables, added to nav, can be accessed using the object that
// nav refers to in global scope (see the end).
nav.CLASS = 'js-nav-open';
...
// This function is also added to nav, therefore it can be accessed outside
nav.toggle = function(event) {
...
// This reference to _isNavOpen resolves because this function
// is a closure, and binds variables outside its scope
// to the function itself. So even though _isNavOpen can't be
// accessed globally, it can be accessed here, making it like
// a private member of this namespace.
if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
// nav is also bound by the closure and can be accessed here
nav.close();
} ...
};
Use in global space:
}(PROJECT_NAME));
console.log(PROJECT_NAME.nav.CLASS); // "js-nav-open"
console.log(PROJECT_NAME.nav.toggle); // Function object
This is a module pattern. It is used for several reasons:
Code portability (not referring to global objects inside the module)
Scoping (avoiding assigning unnecessary vars to global namespace)
Visibility (hiding private access variables)
As for the first three lines themselves (your original question), they could refer to PROJECT_NAME directly, but it looks like it's been set up to aid code portability. You'll notice that the anonymous function itself never points to the real object (PROJECT_NAME). That means that you can copy and paste this part around and only change that reference in one place.
The other answer mentions scope, and while that's important too, it doesn't explain all benefits of this code, such as why it doesn't just directly refer to existing global variables. The scope-hiding benefits themselves are achieved with this part of the pattern:
(function() {
... // Anything set here is local, not global.
})();

Should I use window.variable or var?

We have a lot of setup JS code that defines panels, buttons, etc that will be used in many other JS files.
Typically, we do something like:
grid.js
var myGrid = .....
combos.js
var myCombo = .....
Then, in our application code, we:
application.js
function blah() {
myGrid.someMethod()
}
someother.js
function foo() {
myCombo.someMethod();
myGrid.someMethod();
}
So, should we be using the var myGrid or is better to use window.myGrid
What's the difference?
A potentially important difference in functionality is that window.myGrid can be deleted, and var myGrid can not.
var test1 = 'value';
window.test2 = 'value';
console.log( delete window.test1 ); // false ( was not deleted )
console.log( delete window.test2 ); // true ( was deleted )
console.log( test1 ); // 'value' ( still accessible )
console.log( test2 ); // ReferenceError ( no longer exists )
I would suggest creating a namespace variable var App = {};
App.myGrid = ...
That way you can limit the pollution of the global namespace.
EDIT: Regarding the number of variables issue - 2 possible solutions come to mind:
You can further namespace them by type(Grids, Buttons, etc) or by relationship(ClientInfoSection, AddressSection, etc)
You encapsulate your methods in objects that get instantiated with the components you have
ex: you have
function foo() {
myCombo.someMethod();
myGrid.someMethod();
}
becomes:
var Foo = function(combo, grid) {
var myCombo = combo;//will be a private property
this.myGrid = grid;//will be a public property
this.foo = function() {//public method
myCombo.someMethod();
myGrid.someMethod();
}
}
App.myFoo = new Foo(someCombo, someGrid);
App.myFoo.foo();
this way you limit the amount of little objects and only expose what you need (namely the foo function)
PS: if you need to expose the internal components then add them to this inside the constructor function
One nice use of window.variable is that you can check it without having a javascript error. For example, if you have:
if (myVar) {
//do work
}
and myVar is not defined anywhere on the page, you will get a javascript error. However:
if (window.myVar) {
//do work
}
gives no error, and works as one would expect.
var myVar = 'test' and window.myVar = 'test' are roughly equivalent.
Aside from that, as other said, you should descend from one global object to avoid polluting the global namespace.
In global scope the two are in fact equivalent functionality-wise. In function scope, var is certainly preferable when the behaviour of closures is desired.
I would just use var all of the time: firstly, it's consistent with the usually preferred behaviour in closures (so it's easier to move your code into a closure if you decide to do so later), and secondly, it just feels more semantic to me to say that I'm creating a variable than attaching a property of the window. But it's mostly style at this point.
The general answer to the question would be to use var.
More specifically, always put your code in an Immediately Invoked Function Expression (IIFE):
(function(){
var foo,
bar;
...code...
})();
This keeps variables like foo and bar from polluting the global namespace. Then, when you explicitly want a variable to be on the global object (typically window) you can write:
window.foo = foo;
JavaScript has functional scope, and it's really good to take full advantage of it. You wouldn't want your app to break just because some other programmer did something silly like overwrote your timer handle.
In addition to other answers, worth noting is that if you don't use var inside a function while declaring a variable, it leaks into global scope automatically making it a property of window object (or global scope).
To expand on what Liviu said, use:
App = (function() {
var exports = {};
/* code goes here, attach to exports to create Public API */
return exports;
})();
By doing that you can hide some of your implementation specific code, which you may not want exposed by using var's inside. However, you can access anything attached to the exports object.

I've Heard Global Variables Are Bad, What Alternative Solution Should I Use?

I've read all over the place that global variables are bad and alternatives should be used. In Javascript specifically, what solution should I choose.
I'm thinking of a function, that when fed two arguments (function globalVariables(Variable,Value)) looks if Variable exists in a local array and if it does set it's value to Value, else, Variable and Value are appended. If the function is called without arguments (function globalVariables()) it returns the array. Perhaps if the function is fired with just one argument (function globalVariables(Variable)) it returns the value of Variable in the array.
What do you think? I'd like to hear your alternative solutions and arguments for using global variables.
How you would use globalVariables();
function append(){
globalVariables("variable1","value1"); //globalVariables() would append variable1 to it's local array.
};
function retrieve(){
var localVariable1 = globalVariables("variable1"); //globalVariables() would return "value1".
};
function retrieveAll(){
var localVariable1 = globalVariables(); //globalVariables() would return the globalVariable()'s entire, local [persistently stored between calls] array.
};
function set(){
globalVariables("variable1","value2"); //globalVariables() would set variable1 to "value2".
};
Is this a Singleton Pattern BTW?
In this specific scenario a function may set a variable at one point in time, and much later another function, maybe when a user submits a form, will need to get that variable. Therefore the first function couldn't pass the variable as an argument to the later function as it would never be called from the first.
Thank you, I appreciate all your help!
The primary reason why global variables are discouraged in javascript is because, in javascript all code share a single global namespace, also javascript has implied global variables ie. variables which are not explicitly declared in local scope are automatically added to global namespace. Relying too much on global variables can result in collisions between various scripts on the same page (read Douglas Crockford's articles).
One way to reduce global variables is to use the YUI module pattern. The basic idea is to wrap all your code in a function that returns an object which contains functions that needs to be accessed outside your module and assign the return value to a single global variable.
var FOO = (function() {
var my_var = 10; //shared variable available only inside your module
function bar() { // this function not available outside your module
alert(my_var); // this function can access my_var
}
return {
a_func: function() {
alert(my_var); // this function can access my_var
},
b_func: function() {
alert(my_var); // this function can also access my_var
}
};
})();
now to use functions in your module elsewhere, use FOO.a_func(). This way to resolve global namespace conflicts you only need to change the name of FOO.
Semantics my boy. Semantics.
Start with one global: myApp = {};
Everything should be in that. The only exception would be your AJAX library (there are some extreme exceptions like working with JSONP callbacks).
There should be very few properties in myApp. You'll want to hold your application properties in containers such as config or settings.
myApp = {
config:{
prop:1
},
settings:{
prop:2
},
widgets:{
List: function(props){},
Item: function(props){}
}
}
Then you may have more properties in lower modules, components, singletons and Class constructors (widgets).
This setup gives you the added benefit of being able to access any property from any other location since you can get it with the myApp global. However, you should use "this" whenever possible because the lookup is faster. And just set the property directly, don't bother with the pseudo getter/setter stuff. If you really need a getter/setter, code it for that specific use.
The reason your example doesn't work is it's too generic and you seem to be looking for an excuse to work in the global space.
And don't get clever with private variables. They're bad too:
http://clubajax.org/javascript-private-variables-are-evil/
Global state causes problems in several areas. One is code reuse. When you access some global state that means the component must be aware of it's environment(something outside of itself). You should avoid this as much as possible, because it makes the component unpredictable.
Say I have an object that accesses your globalVariables function and I want to use it in another page. How do I know to define the globalVariables object or even how to define it? However if you can pass the information into a constructor or as an argument to a function then I can easily determine what is required by the object.
Also when you access or modify the global scope then you risk affecting other objects. This is why libraries like jquery use only a single name on the global scope(the least possible). It lessens the possibility of conflict with other libraries. In other words the global scope is out of your control, so it is dangerous.
Using global variables is generaly speaking a bad practice, regardless of the language of choice. They are not even (easily) allowed to use when at strict mode, which I highly recommend.
Consider this piece of code I found:
if (typeof session != 'undefined' && !data.cart.request_status)
data.input_definitions.passengers =
inflate_passenger(session, data.input_definitions.passengers);
I needed to turn around and ask a felow programmer where did this session variable came from, as no code search showed up where was set.
I turned out another package from the company sets the global variable.
Code it's like a joke: if you need to explain it it's probably not that good.
Workaround using ES6:
If at Node, use import or require to bring the desired stuff into lexical scope, don't let people touch your global environment without you knowing it.
import {Sesssion} from 'api-core';
const Session = require('api-core').session;
If you are at the frontend delivering code for the browser you can't use import unless you transpile your ES6 code using Babel.
Example transpiling using Gulp.js:
// $ npm install --save-dev gulp-babel babel-preset-es2015
// gulpfile.js
const gulp = require('gulp');
const babel = require('gulp-babel');
gulp.task('transpile', () => {
return gulp.src('src/app.js')
.pipe(babel({presets: ['es2015']}))
.pipe(gulp.dest('dist'));
});
// $ gulp transpile
Legacy workaround:
When using ES6 features is not an option the only workaround to using a bunch of global variables, is using only one, and have hope:
// scripts/app.js
var MyApp = {
globals: {
foo: "bar",
fizz: "buzz"
}
};
var ASHIVA_HandsOffNHS = (function() {
// VARIABLES
var my_var = 10;
// PRIVATE FUNCTIONS
function bar() {
console.log(my_var + 5);
}
// PUBLIC OBJECT
myObject = {};
myObject['a_func'] = function() {
my_var += 10;
console.log(my_var);
};
myObject['b_func'] = function() {
my_var = 0;
console.log(my_var);
};
return myObject;
})();
ASHIVA_HandsOffNHS.a_func();
ASHIVA_HandsOffNHS.b_func();
ASHIVA_HandsOffNHS.a_func();
The issue with your solution is that it just makes you code harder to understand while still keeping all the downsides of global variables. The page you linked to covers the problems. The only problem your proposed solution really solves is namespace pollution but at the cost of not being able to see what global variables are declared as easily as the declaration is a function call).
The solution is to write code without global variables. If a function needs a value pass it as a argument.
You really don't want to do this.
As to why see e.g. the top post here: What is the most EVIL code you have ever seen in a production enterprise environment?
As a side note, one can always execute "global" code without littering the place with globals:
(function() {
var notaglobal = 1;
alert(notaglobal);
})();
//notaglobal is not defined in this scope
Other answer most explain with anonymous function as this article mention,
Anonymous functions are difficult to debug, maintain, test, or reuse.
Here are example with normal function. It's easier to read and understand.
/* global variable example */
var a= 3, b= 6;
function fwithglobal(){
console.log(a, b); // 3 6 expected
}
fwithglobal(); // first call
function swithglobal(){
var a=9;
console.log(a, b); // not 3 6 but 9 6
}
swithglobal(); // second call
/* global variable alternative(function parameter) */
function altern(){
var a= 3, b= 6; // var keyword needed
f_func(a,b);
s_func(a,b);
}
function f_func(n, m){
console.log(n, m); // 3 6 expected
}
function s_func(n, m){
var a=9;
console.log(n, m); // 3 6 expected
}
altern(); // only once
Global variables are bad... if left unmanaged!
The potential risks of global variables is as high as the pleasure and productivity gains of having frequently used objects ready to use.
I don't believe one should seek a single alternative. Instead I advocate for one object in charge of managing those globals and as the code base/component matures, refactor them out
One thing not mentioned in the current answers which I think is critical is an understanding of DI and IoC containers. These address many of the problems people try to solve with global variables, but covering related concerns that plain globals can't, like object life cycles.

Categories

Resources