0

I'm a noob in js, some background with processing.org, wich is a framework for java. I'm trying to understand the code below, from an example that came with processing. Now I did a little dig in javaScript. But this..

var someName = (function(){..code, code, code...})());

got me confused.

I know

var name = function(){} // builds a function

or

var name = {code}// makes obj

and even

function name(...){...}//an obj

but... so the stuff between parenthesis is replacing the arguments? I don't get it.

below is the full code (i mean just this function, the code is intended to communicate html input tags with processing running in processing.js in browser it can be seen running here all the code linked from there also)

Any help appreciated. thanks

var Controller = (function(){

    function Controller () {
        var sketch = arguments[0];
        var form = document.getElementById(arguments[1]);
        form.onsubmit = function () {return false};
        var inputs = {};

        this.createInputElement = function ( id, type, labelStr ) {
            var input = document.createElement('input');
            input.id = id;
            input.name = id;
            input.type = type;
            if ( labelStr !== undefined && labelStr !== '' )
            {
                var label = document.createElement('label');
                label['for'] = id;
                label.id = id+'-label';
                label.innerHTML = labelStr;
                form.appendChild(label);
            }
            form.appendChild(input);
            return input;
        }

        this.addInputField = function ( l, t ) {
            var id = createIdFromLabel(l);
            if ( inputs[id] == undefined ) {
                inputs[id] = this.createInputElement(id, t, l);
                inputs[id].onchange = function(){
                    changeFunc()(sketch, id, this.value);
                    return false;
                }
            }
            return inputs[id];
        }

        this.addRange = function ( l, c, mi, mx ) {
            var input = this.addInputField( l, "range" );
            input.value = c;
            input.min = mi;
            input.max = mx;
            return input;
        }

        this.addPassword = function ( l ) {
            var input = this.addInputField ( l, "password" );
            return input;
        }

        this.addEmail = function ( l ) {
            var input = this.addInputField ( l, "email" );
            return input;
        }

        this.addSearch = function ( l, c ) {
            var input = this.addInputField ( l, "search" );
            input.value = c;
            return input;
        }

        this.addNumber = function ( l, c ) {
            var input = this.addInputField ( l, "number" );
            input.value = c;
            return input;
        }

        this.addTelephone = function ( l, c ) {
            var input = this.addInputField ( l, "tel" );
            input.value = c;
            return input;
        }

        this.addUrl = function ( l, c ) {
            var input = this.addInputField ( l, "url" );
            input.value = c;
            return input;
        }

        this.addDate = function ( l, c ) {
            var input = this.addInputField ( l, "date" );
            input.value = c;
            return input;
        }

        this.addCheckbox = function ( l, c ) {
            var id = createIdFromLabel(l);
            if ( inputs[id] == undefined ) {
                inputs[id] = this.createInputElement(id, "checkbox", l);
                inputs[id].onchange = function(){
                    changeFunc()(sketch, id, this.checked);
                    return false;
                }
            }
            inputs[id].checked = c ? 'checked' : '';
            return inputs[id];
        }

        this.addTextfield = function ( l, c ) {
            var id = createIdFromLabel(l);
            if ( inputs[id] == undefined ) {
                inputs[id] = this.createInputElement(id, "text", l);
                inputs[id].onchange = function(){
                    changeFunc()(sketch, id, this.value);
                    return false;
                }
            }
            inputs[id].value = c;
            return inputs[id];
        }

        this.addTextarea = function ( l, c ) {
            var id = createIdFromLabel(l);
            if ( inputs[id] == undefined ) {
                var label = document.createElement('label');
                label['for'] = id;
                label.id = id+'-label';
                label.innerHTML = l;
                form.appendChild(label);
                inputs[id] = document.createElement('textarea');
                inputs[id].id = id;
                inputs[id].name = id;
                inputs[id].innerHTML = c;
                inputs[id].onchange = function(){
                    changeFunc()(sketch, id, this.value);
                    return false;
                }
                form.appendChild(inputs[id]);
            }
            inputs[id].value = c;
            return inputs[id];
        }

        this.addSelection = function ( l, o ) {
            var id = createIdFromLabel(l);
            if ( inputs[id] == undefined ) {
                var label = document.createElement('label');
                label['for'] = id;
                label.id = id+'-label';
                label.innerHTML = l;
                form.appendChild(label);
                var select = document.createElement('select');
                select.id = id;
                select.name = id;
                if ( o !== undefined && o.length && o.length > 0 ) {
                    for ( var i = 0; i < o.length; i++ ) {
                        var value = o[i].length > 1 ? o[i][1] : i;
                        var option = document.createElement('option');
                        option.innerHTML = o[i][0];
                        option.value = value;
                        select.appendChild(option);
                    }
                }
                select.onchange = function( event ){
                    changeFunc()(sketch, id, this.value);
                    return false;
                }
                inputs[id] = select;
                form.appendChild(inputs[id]);
            }
            return inputs[id];
        }
        this.addMenu = this.addSelection;

        this.setElementLabel = function ( element, labelStr ) {
            var label = document.getElementById(element.id+'-label');
            if ( label && label.childNodes && label.childNodes.length > 0 ) {
                label.childNodes[0].textContent = labelStr;
            } else {
                //console.log([element, label]);
            }
        }
    }

    var changeFunc = function () {
        return function ( sketch, id, value ) {
            try {
                sketch[id](value);
            } catch (e) {
                //console.log(e);
                sketch.println( "Function \"void "+id+"(value)\" is not defined in your sketch.");
            }
        }
    }

    var createIdFromLabel = function ( l ) {
        return l.replace(/^[^-_a-z]/i,'_').replace(/[^-_a-z0-9]/gi,'');
    }

    return Controller;

})();
v.k.
  • 2,826
  • 2
  • 20
  • 29
  • 3
    http://en.wikipedia.org/wiki/Immediately-invoked_function_expression – elclanrs Sep 26 '13 at 23:27
  • 3
    Read about the module pattern in JavaScript and please do not follow this code as an example. Defining functions inside the constructor is so inefficient. – plalx Sep 26 '13 at 23:34
  • @plalx +1, the only time I think that pattern is okay is if the _IIFE_ does `return new Construtor()`, rather than `return Constructor` - i.e. the constructor in the _IIFE_ gets invoked only once to generate some unique _Object_ that would have been difficult to make without an _IIFE_. – Paul S. Sep 26 '13 at 23:54
  • thanks guys, I gonna look into those (including the dupe), and get back here if I need more help. – v.k. Sep 27 '13 at 00:54
  • @elclanrs is there anything I should do about being a duplicate? – v.k. Sep 27 '13 at 01:27

2 Answers2

1

that is an immediate function, which is invoked immediately after declaring, the value assigned to the variable is the one returned by this immediate function (in your code that would be the inner Controller function). this construct is used to create a closure scope, where you can declare variables that are shared by all internal functions but are unavailable in the global scope.

BTW {} isn't a class, it's an object. Javascript has no notion of classes; it uses prototypes

Nicolas Straub
  • 3,381
  • 6
  • 21
  • 42
0

As others have said, this is a immediately invoked function expression. It is basically equivalent to

var controllerFactory = function() {
    function Controller() {
        //Code code code
    }

    return Controller;
};

var Controller = controllerFactory();

The only difference is that you don't need the variable controllerFactory with the IIFE. For your reference there is another common form for IIFEs which looks like this

!function(params...) {
    //code code code
}(args...);

A more concrete example would be

!function($, undefined) {

}(window.jQuery);

This makes sure that the $ inside your IIFE is indeed jQuery and that undefined is the true undefined.

tleef
  • 3,516
  • 1
  • 24
  • 34