How to avoid global variables? - javascript

I've been told not to use global variables.
I use one to turn off/on client side validation.
I use two more to conrol me drop-down menu.
If these should not be gloval variables where should I put them?
/*
Global
*/
var client_validation=1, // used to turn off/on client-side validation
menu_timer=0,
menu_elment=0;
window.onload=i0;
/*menu*/
function top_mouse_over(id)
{
bottom_mouse_over();
if(menu_element)menu_element.style.visibility='hidden';
menu_element=document.getElementById(id);
menu_element.style.visibility='visible';
}
function internal_time()
{
if(menu_element)menu_element.style.visibility='hidden';
}
function mouse_out()
{
menu_timer=window.setTimeout(internal_time, 500);
}
function bottom_mouse_over()
{
if(menu_timer)
{
window.clearTimeout(menu_timer);
menu_timer=0;
}
}
Header 1 // This makes more sense
Content
Header 1 // Than this
Content

It sounds to me like you those might be good candidates for globals. Globals are supposed to, well, be reserved for operations with broad implications for the app like controlling fundamental behavior across multiple pieces.
Now, if you want to create a "namespace" for them, it's this simple:
var globalControls = {
client_validation:1,
menu_timer:0,
menu_elment:0,
window_onload:i0
};
Javascript doesn't have real namespaces yet. Objects are used as a substitute for them until the next version of ECMAScript might get around to adding that feature.

Here is an article about javascript namespacing.
http://javascriptweblog.wordpress.com/2010/12/07/namespacing-in-javascript/

The title should be "How do I avoid global variables"? But that's ok.
You can create an object and assign properties to it. Then you'll have variables inside an object and these variables will only be accessible through this one, not through the global scope.
Example:
var config = {
clientValidation: true,
menuTimer: 0,
menuElement: 0,
someFunction: function () {
// alert (this.clientValidation) "this" is the object scope
}
};
// then you access the object properties:
alert( config.clientValidation ); // true

namespacing separates class definitions from colliding, however, it will not solve the global variable problem. It is a temporary fix.
A solution to global variables is to use a class instance which encapsulates properties that would otherwise be global. Encapsulation is one of the 3 pillars of object oriented programming.
See for an example of a class with a namespace that has encapsulated properties.
Additionally, I show how to create a custom jquery plugin that uses the class.
http://www.robusthaven.com/blog/javascript-development/Automatically-generate-the-table-of-contents-with-jQuery
When i have data that i need persisted that would normally require creating a global variable I instead use http://api.jquery.com/jQuery.data/ to attach the data in an object form to the dom element making use of this data.

Related

Need advise/help on getting rid of global variables

Yes, this is another topic about global variables. I've searched quite a bit about them. But most of the topics is just about WHY not to use global variables and I'm convinced that I shouldn't, and I am more wondering HOW not to use them, and that I'm still unsure about.
I am working on a project, and it works wonders, but I am using about 50 global variables at the moment and that number keeps rising. Right now I've split things up in multiple .js files. Like load_chunks.js, load_images.js, render_map.js, player_actions.js, input.js, to spread the functions based on what they are for. And I've put all global variables inside settings.js.
Currently I use these global variables for these reasons:
1. Calculation based on some other global variables that doesn't change much or at all after loading. By doing this once, and store it in a global variable, I no longer have to repeat the calculation ever again. If I didn't store it in a (global) variable, Javascript would have to do the calculation many times each second, in some cases even up to few thousand times per second.
2. When the global variable is needed in many functions. Like there's this World-variable, that I use to hold data for the appearance of the world. This variable is a multidimensional array. World[y][x] for example. Load_chunks.js adds more data to this variable, or remove data if you move too far. This variable is also needed in render_map.js, to create the map, and it's also needed in player_action.js, to see if you can step on that particular location.
3. Settings; So a number in a variable that remains the same unless I change them in my script. Instead of going through my scripts, and change the numbers manually after a long search and thinking what the number was, I've put that number in 1 variable and call that variable numerous times in my scripts. These variables are in some cases also needed elsewhere.
Also I like to mention that I don't use classes, and perhaps for that reason I never got around using global variables...?
So how do I get rid of my global variables, or shouldn't I?
I hope you can show me or write for me a script example (or a link to it) of how I should do it. That's the fastest way I learn.
Put Variables Inside a Function Closure
One common way to eliminate a global is to put is inside a function closure:
(function() {
var declareYourFormerGlobalHere = 0;
// put all code that uses the variable inside this closure
// the variable persists for this code to use, but is not actually global
})();
Here's are some usage examples:
// example keeping track of a running count and a cached DOM element
(function() {
var cntr = 0, obj = document.getElementById("test");
setInterval(function() {
++cntr;
if (obj.value < cntr) {
// do something
} else {
// do something else
}
}, 1000);
})();
// example keeping track of a time of last click
(function() {
var timeOfLastClick = 0;
document.getElementById("run").addEventListener("click", function(e) {
var now = new Date().getTime();
// only process click if more than 2 seconds have passed since last click
if (now - timeOfLastClick > 2000) {
// OK to process the click
}
timeOfLastClick = now;
});
})();
Sometimes, you can actually enclose all your code or nearly all your code in a single closure like this and all your current globals become local variables inside the closure rather than actual globals. jQuery uses this technique to declare lots of persistent variables it uses, none of which are actual globally scoped.
Use a Single Namespace Object
Another common method of reducing the number of globals is to use the namespace concept. In this concept, you declare a single global object and put other persistent variables as properties of this single global object. This still leaves you with a single global variable, you can have as many properties as you want off this single global.
var myNamepaceObject = {};
myNamespaceObject.var1 = "foo";
myNamespaceObject.var2 = "whatever";
This technique is also used by jQuery as all globally accessible functions that jQuery offers are available off the jQuery object such as jQuery.extend() or jQuery.contains(). jQuery exposes a single global variable and many other globally accessible functions are then available as properties of that single global object.
Module Pattern
What is commonly known as the "module pattern" uses a combination of these above two techniques, where you have a single module variable that both uses properties and closure variables.
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
You can see a discussion of this design pattern in these references:
JavaScript Module Pattern: In-Depth
Learning Javascript - The Module Pattern
Mastering the Module Pattern
JavaScript module pattern with example
I'm convinced that I shouldn't, and I am more wondering HOW not to use them, and that I'm still unsure about.
load_chunks.js, load_images.js, render_map.js, player_actions.js, input.js, strongly hint to a procedural implementation, that is your architecture probably has several functional pieces and you pass data around between these functions. That's where your global variables are coming from.
So how do I get rid of my global variables (...)
To change that, you need to structure your system in an object or component based approach, that is:
encapsulate data + respective functions by objects in your problem domain, e.g. have a World object that contains Avatar, Buildings, Airborne objects etc. (or whatever your project is about).
separate the problem domain's logic from view logic (e.g. use a MVC architecture)
then your project organises the interactions between view and model objects by essentially exchanging messages between them.
To facilitate this, I suggest these fine frameworks, or some equivalents suitable for your run-time environment:
requirejs - to encapsulate modules into globally managed components
backbonejs - to have an efficient, proven model/view, class/object model (actually built for use with a REST-style backend, but that's not a strict requirement)
Code structure
Typically, I structure my applications such that there is one .js file per each object component/module. A module in this sense contains both the class definition and the corresponding collection. The modules are managed by requirejs and the class definitions are done using backbonejs.
I hope you can show me or write for me a script example
/* define a class e.g. in someclass.js */
define(['backbone'], function($B) {
var SomeClass = $B.Model.extend({
// all instance variables, methods etc. follow
someVar : value,
someMethod : function() { ... },
});
return SomeClass;
});
/* use the class, e.g. in app.js */
require(['someclass'], function(SomeClass) {
var instance = new SomeClass({ initial model attributes });
var value = instance.get('attribute');
instance.someMethod();
...
});
i had the same problem before but it was a big problem as we had a third party javascript code and our code live in clients websites so we should find a way to omit the appearance of global variable so to be short:
Use 1 global variable namespace and make all other to be properities for it:
GlobalVariable = {}
GlobalVariable.var1 = "var1"
GlobalVariable.var2 = "var2"
You can also make it more useful and divide it into groups:
GlobalVariable.helper = {}
GlobalVariable.helper.var1 = "var1"
GlobalVariable.helper.var2 = "var2"
so you can use same names under different groups.
and if you want to Omit it totally you can use:
(function(document, window) {
// all variables here is global only inside the scope
}(document, window));

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.
})();

What is the best way to manage variable in memory for Javascript

I'm building a web application that is heavily based on the browser via Javascript.
When I need a module located in a separated file, I don't know which of the three methods is the best regarding the memory taken by the javascript engine :
Idea 1, assign variables in the extend method
function (ContactCollection , ItemCollection, ContactListView) {
var ContactExample = function (inst) {
// Wild examples of possible uses :
this.collections.contact.each(function(model) {
// do something with each model
});
this.collections.item.on('reset', this.resetItems, this);
this.$el.remove().append(this.view.render().el);
};
jQuery.extend(true, ContactExample.prototype, {
'collections': {
'contact': ContactCollection,
'item': ItemCollection
},
'view': ContactListView,
'$el': jQuery('#somediv'),
}, ContactExample);
return new ContactExample();
};
Idea 2, assign variables in the instanciation method :
function (ContactCollection , ItemCollection, ContactListView) {
var ContactExample = function (inst) {
// Wild examples of possible uses :
inst.collections.contact.each(function(model) {
// do something with each model
});
inst.collections.item.on('reset', this.resetItems, this);
inst.$el.remove().append(this.view.render().el);
}
jQuery.extend(true, ContactExample.prototype, {
'$el': jQuery('#somediv')
}, ContactExample);
return new ContactExample({
'collections': {
'contact': ContactCollection,
'item': ItemCollection
},
'view': ContactListView
});
};
Idea 3, simply use them in the code, since they are already referenced in the scope of the function :
function (ContactCollection , ItemCollection, ContactListView) {
var ContactExample = function (inst) {
// Wild examples of possible uses :
ContactCollection.each(function(model) {
// do something with each model
});
ItemCollection.on('reset', this.resetItems, this);
this.$el.remove().append(ContactListView.render().el);
}
});
jQuery.extend(true, ContactExample.prototype, {
'$el': jQuery('#somediv')
}, ContactExample);
return new ContactExample();
});
What (and why) is the best way to handle variable in the javascript memory engine.
Thank you for your answers
The lowest memory use of your three options would be to use the context variables (idea #3), since it eliminates duplication. The other two copy the values to a second object created inside of that function. Here's the background:
Everything in JavaScript is an object and objects are internally just hashmaps relating string keys to a reference to its actual value. This includes ordinary local variables; internally they're properties on an invisible context object that can be accessed by that function and any functions defined inside of it. Using $.extend vs assigning properties directly makes no difference, because the extend function is just syntactic sugar around a for loop that copies properties from one object to another.
Since a function's context (local variable) object is retained for use by all functions defined inside of it, the lowest memory usage of your options would be the one that doesn't duplicate it to new internal objects. But the difference would be minor.
If you really want to cut your memory usage to the smallest level and write easier-to-maintain code, I'd suggest getting rid of the fancy (and hard-to-debug) context wrapping and code it the old fashioned JavaScript OOP way: use an ordinary constructor defined either at the top level or inside a single wrapper function that's run only once when the page is first loaded. That gets rid of the duplicate contexts. Call it with the 'new' keyword and pass in data as arguments that you assign to 'this'. Do your initialization inside of the constructor, and nothing more.
Put all of your method functions on its prototype and then use it as a normal, ordinary, no-frills JavaScript object.
https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript
Why are you using $.extend at all? Just create an instance and assign the properties:
var c = new ContactExample();
c.$el = $('#somediv');
Memory won't be a problem - instead focus on the references to DOM-elements (#somediv) that may cause the troubles later.
Constants
If you don't need them outside of the scope of the function, then use normal variables.
If you need them outside of the scope of the function, then put them on the constructor.
Instance variables (that change with each instance)
For properties that you know will have different values for each instance, declare them with the proper type in the constructor so that they can be optimized into the static type associated with the constructor.
For properties that are shared among all objects (like methods), use the prototype.
For properties that will more likely keep their default value, if you want speed of access, you should declare them in the constructor, but if you want to use far less memory, you should put the default values on the constructor and only add a property to the object if it differs from the default value.

Can I add attributes to 'window' object in javascript?

Can I add any random attribute to 'window' object in javascript? Some thing like:
window.my_own_attr = "my_value"
Does it have any side effects with any libraries? And is it cross-browser compatible?
Can I add any random attribute to 'window' object in javascript?
Yes, just like you've shown.
Does it have any side effects with any libraries?
No, not unless you use a library which sets a property you then overwrite.
And is it cross-browser compatible?
Yes, completely.
Having said that, this practice is generally frowned upon. You could end up overwriting something you don't want to.
In all browsers, window is the javascript global namespace. Every property or method 'lives' in that namespace. So if you assign a property to window, it is in effect a global variable.
example:
window.myConstant = 5;
// note: a var declaration will be a window property too
// note 2: 'let' or 'const' will not be window properties
// below can also be done without 'var'.
var myConstantGlobal = 4;
console.log(`multiply(10) => ${multiply(10)}`);
console.log(`multiply() => ${multiply()}`);
console.log(`multiplyGlobalVar(10)) => ${multiplyGlobalVar(10)}`);
console.log(`multiplyGlobalVar() => ${multiplyGlobalVar()}`);
function multiply(val){
return myConstant * (val || 1);
}
function multiplyGlobalVar(val){
return window.myConstantGlobal * (val || 1);
}
You have to be cautious with javascript frameworks. For instance, if you declare window.JQuery, and use the JQuery framework, the JQuery namespace will be replaced by your assignment, rendering it useless.
Yes, you can, but in general you shouldn't.
The window object is also the JS default "global" object, so all global variables get added there.
You're unlikely to break anything unless you overwrite a property that's already there, but it's considered bad practise to dump variables on window, or otherwise create lots of global variables.
I won't repeat what others have said re: the hackyness of this practice. But it can be incredibly useful when using a rigid framework like Angular mixed with vanilla HTML / JS (or jQuery) code. Which is also hacky and frowned upon, but sometimes there are good reasons, like if you have lots of pre-existing JS code that will be challenging to integrate into the framework.
The more interesting question to me is HOW to make use of the ability to add properties to the global window object. There is a pattern I use when I want to expose the methods of an Angular provider (service) to code that otherwise would be unable to inject the service, probably because it runs outside of the Angular DI framework. The way I do it is as follows:
Define your service as a provider in your top level module.
In the constructor or onInit of app.component.js (or whatever your top level component is that imports the provider), inject the provider normally, perform any one time initialization that it needs, and then call window['MyServiceName'] = this
Assuming you have designed the provider to follow a Singleton pattern, your provider's methods can now be safely called from anywhere. A non-Angular script need simply call window['MyServiceName'].methodName()
That 'll work fine, no conflict with any library until used same variable name, will work in all browsers, but not recommended as this will create global JS variable.
In IE if an element has an id, then that node is accessible on the window object as a property:
<div id="num"></div>
alert(num); //Element
num = 3; //throws exception
var num = 3; //ok
As pointed out by others yes you can and yes it means adding "global variables".
Having global variables is not best practice but sometimes it is the simplest thing to do. For instance if you use IFrames and want the child-window to access some property of the parent window. Such a property must be "global" for a child to access it. But this also shows that it is not "truly global", it is just a property of a specific window. But it can conflict with other property-names such as names of functions defined in the same window, perhaps by some libraries you use.
So we know global variables are bad. If we decide to use them anyway is there anything we can do to minimize their badness?
Yes there is: Define a SINGLE global variable with a more or less unique name, and store an OBJECT into it. Store all other "variables" you need as fields of that single object.
This way you don't need to ever add more than a single global variable (per window). Not TOO bad.
Name it more or less uniquely so it is unlikely to conflict with anybody else's single global. For instance you could use your name + 's' as the variable name:
window.Panus = {};
:-)

Object Orientated Javascript / Variable declarations / Performance

So I have a rather large object orientated javascript class, with about 120 functions (a lot of getters and setters). Some of these functions have variables that are basically constants.
What I'm wondering, is should I declare these variables in a global scope of the object, so every time the function is run it doesn't have to re-declare the variable?
An example function is below. this.displayContacts is run several times (and will always run within the object), so in this case, there's no point declaring the 'codes' object inside the function?
function orderObject() {
this.displayContacts = function() {
var codes = {'02':'02','03':'03','07':'07','08':'08'};
// do something with codes
};
}
So, would this be better, performance wise?
function orderObject() {
var codes = {'02':'02','03':'03','07':'07','08':'08'};
this.displayContacts = function() {
// do something with codes.
};
}
My other concern is that if I end up with a lot of global variables/objects inside the main orderObject, will that be MORE of a performance hit than simply re-declaring the variables each time?
absolutely.
function MyClass() {
this.somevar = ''; // instance scoped variable
};
MyClass.CODES = {'02':'02'...}; // 'Class' scoped variable; one instance for all objects
MyClass.prototype.instanceMethod = function(){
// 'this' refers to the object *instance*
// it can still use MyClass.CODES, but can also account for variables local to the class
}
CONSTANT is 'static' so to speak, in java-talk. If your codes are global to the class (and the rest of your application), you will save a lot of overhead this way -- only define the object once. Note that you can have 'static' class-level methods as well, for those cases where the function doesn't need to operate on variables specific to an instance of the class.
Unless your app is really beefy, performance optimization probably wont make it noticeably faster. But that doesn't mean that OO design is not worth-while -- if you are going to use javascript in an object oriented way, its not too hard and never a bad idea to use good OO principals.
I would say that if you have something that you are using in multiple places that it should become a property of your object so that it doesn't have to be redeclared each time. It would also help make the maintenance of the object easier if that constant has to change. Then you are changing it only in one place and not having to hunt down all the locations where you used it.
Don't repeat yourself.
Garbage collection in JavaScript depends on the browser, and most modern browsers handle it pretty well. If you go ahead and make these global, you might see a slight performance increase simply because it's not executing that line of code every time. However, I can't imagine any significant increase in performance by making these static properties on the class, but if they don't change, then it would make more sense.

Categories

Resources