Search code examples
javascriptfunction-prototypes

Javascript Callable and prototype extendable Function


Basically I looking for the ability to attach methods to an executable function while using the javascript prototype method. The code below demonstrates want I'm talking about and the functionality I'm looking for, but it is really a hack. Notice I have a valid this object to attach variables along with a main and init function.

function create(){
    var $this = {},
    main = function(){
        prototype.main.apply($this,arguments);
    };
    prototype.init.apply($this,arguments);
    //Add additional prototype methods by brute force, ugly
    for(i in prototype)-function(i){
        main[i]=function(){
            prototype[i].apply($this,arguments);
        }
    }(i);
    return main;
};

var prototype = {
    //called when you create the object
    init:function(text){
        console.log('init');
        this.text = text;
    },
    //called when you call the object
    main:function(){
        console.log('main');
        console.log(this);
    },
    method:function(){
        console.log(this.text);
    }
};

//create returns a function that also has methods
//the below line will call the init method
var fun = create('some variables');
//call main function
fun();
//call methods
fun.method();

I'm afraid I might be missing something obvious.

Here is the same functionality as above, but instead extends the global function prototype.

Extending the global properties is bad practice, so I am looking for a alternative solution.

Function.prototype = {
    //called when you create the object
    init:function(text){
        console.log('init');
        this.text = text;
    },
    //called when you call the object
    main:function(){
        console.log('main');
        console.log(this);
    },
    method:function(){
        console.log(this.text);
    }
};

function create(){
    var ret = function(){
        ret.main.call(main);
    };
    ret.init.apply(main,arguments);
    return ret;
};

//create returns a function that also has methods
//the below line will call the init method
var fun = create('some variables');
//call main function
//fun();
//call methods
fun.method();

Just as an obvious point, it doesn't appear you can use the typical new object approach because if you call new you can't return a separate value.

Any explanation or considerations would be great!


Solution

  • You can put your the prototype functions into the "constructor" body. This technically is what you are currently doing, but defining them explicitly rather than using a helper method is much cleaner. Then, you can further simplify your code using the following pattern for public and private variables and methods:

    function Fun(text) {
        // This is the main function
        var fn = function () {
            return 'main';
        };
    
        // Attach public variables and methods
        fn.publicVariable = 'public';
        fn.publicMethod = function () {
            return text; // text is a "private variable"
        };
    
        // Do whatever initialization
        console.log('init');
    
        // Return the main function     
        return fn;
    }
    
    var fun = Fun('this is some text'); // "init"
    fun() // "main"
    fun.publicMethod() // "this is some text"
    console.log(fun.publicVariable); // "public"
    console.log(fun.text); // undefined