Search code examples
javascriptangularjsprototypeextend

Javascript private functions and object.prototype extend


I have the following angularJS service

define(["angular"], function(Angular) {

var dataStorageService = function() {
    var serviceConstructor = function() {
        var _getColor = function(color) {
            return this.config.categoryColorMapping.colors[color];
        }
    }

    var serviceInstance = new serviceConstructor();

    angular.extend(serviceInstance.prototype, {
        config: {
            numberOfMessagesDisplayed: 5,
            maxTitleLength: 48,
            maxPreambleLength: 140,
            categoryColorMapping: {
                colors : {
                    nyheter: '#2B2B2B',
                    sport: '#F59331',
                    underholding: '#F9B00D'
                },
                categories: {
                    nyheter: _getColor('nyheter'),
                    sport: _getColor('sport'),
                    underholding: _getColor('underholding')
                }
            }
        },
        get: function(param) {
            if(this.config.hasOwnProperty(param)) {
                return this.config[param];
            } else {
                console.warn('Playlist::configService:no "' + param + '" config found');
                return false;
            }
        },
        set: function(param, value) {
            this.config[param] = value;
        }
    });

    return serviceInstance;
};

return dataStorageService;
});

now my goal is to make public the following methods:

  1. get
  2. set

and I want '_getColor' method private but I want to use it within the JSON object config. When I run the code I have

"ReferenceError: _getColor is not defined"

is it possibie to achievie it this way? (to have _getColor private and use it within the JSON object within angular.extend?)


Solution

  • Functions can be shared and still be private, instance specific private members have to be defined in the constructor though. Since your private function doesn't need to access instance specific private members you can do the following:

    define(["angular"], function(Angular) {
    
    var dataStorageService = function() {
        var serviceConstructor = function() {
        }
    
        var serviceInstance = new serviceConstructor();
        //IIFE returning object that will have private members as closure
        // privileged methods have to be in the same function body as the
        // private fucnction
        serviceInstance.prototype = (function() {
            var _getColor = function(instance, color) {
                return instance.config.categoryColorMapping.colors[color];
            };
            return {
              constructor: serviceConstructor
              ,config: {
                numberOfMessagesDisplayed: 5,
                maxTitleLength: 48,
                maxPreambleLength: 140,
                categoryColorMapping: {
                    colors : {
                        nyheter: '#2B2B2B',
                        sport: '#F59331',
                        underholding: '#F9B00D'
                    },
                    categories: {
                        //since categories is a sub object of serviceinstance.categorycolormapper
                        // it is not possible to get the instance of serviceinstance
                        // at this time unless you set it in the constructor
                        // solution could be that each serviceinstance has it's own categorycolormaper
                        // and when categorycolormapper is created pass the serviceinstance instance
                        nyheter: _getColor(this,'nyheter'),
                        sport: _getColor(this, 'sport'),
                        underholding: _getColor(this, 'underholding')
                    }
                }
              },
              get: function(param) {
                if(this.config.hasOwnProperty(param)) {
                    return this.config[param];
                } else {
                    console.warn('Playlist::configService:no "' + param + '" config found');
                    return false;
                }
              },
              set: function(param, value) {
                this.config[param] = value;
              }
            }
        }());
    
        return serviceInstance;
    };
    
    return dataStorageService;
    });
    

    More info on constructor functions and prototype can be found here: https://stackoverflow.com/a/16063711/1641941