Edit in JSFiddle

//définition du code de cache
var cache = (function(){
    
    //variable contenant le cache
    var cache = {}; 
    
    //gestion du cache
    var apply = function(f, hashFunction){
        hashFunction = hashFunction || JSON.stringify || serialize;
        return function(){
            f = f || this;
            var key = f+'('+hashFunction(arguments, ',')+')';
            console.debug(key, cache);
            if(key in cache){
               return cache[key];
            }else{
               return cache[key] = f.apply(null, arguments);           
            }
        }
    }
    
    //sérialisation récursive d'une donnée
    var serialize = function(data, label){
        var result = '';   
        if(data && typeof data === 'object'){ //s'il s'agit d'un objet itérable
            for(var prop in data){               
                result += serialize(data[prop], prop); //appel récursif                
            }
        }else if(data instanceof Array){ //s'il s'agit d'un Array
            for(var i, len = data.length; i<len; ++i){
                result += serialize(data[i], i); //appel récursif                
            }                 
        }else if(typeof data !== 'function'){ //s'il ne s'agit pas d'une fonction
            result += data;
        }
        return result;
    }

    //application au prototype
    Function.prototype.cache = function(){
        return apply();
    }();
    
    //application à la fonction cache
    return apply;
})();

//définition d'une fonction test
var square = function square(x){
    document.write('square('+x+') est appelé');
    return x*x;
}

//appel avec le cache sous forme de méthode
square.cache(2); //affiche square(2) est appelé
square.cache(2); //n'affiche rien => la fonction est bien mise en cache.

//appel avec le cache sous forme de fonction
cache(square)(3); //affiche square(3) est appelé 
cache(square)(3); //n'affiche rien => la fonction est bien mise en cache.

//retour
document.write(cache(square)(2)); //affiche 4
document.write(square.cache(3)); //affiche 9

//utilisation avec un argument de type object
square.cache({prop1:{prop:[]}, prop2:[1,2,{a:'a'}]}); //affiche square([object Object]) est appelé
square.cache({prop1:{prop:[]}, prop2:[1,2,{a:'a'}]}); //n'affiche rien
square.cache({prop1:{prop:[]}, prop2:[1,2,{}]}); //affiche square([object Object]) est appelé