Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 453
Verkade89 Avatar asked Apr 19 '15 16:04

Verkade89


Video Answer


2 Answers

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();
   ...
});
like image 105
miraculixx Avatar answered Sep 28 '22 08:09

miraculixx


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

like image 30
jfriend00 Avatar answered Sep 28 '22 09:09

jfriend00