js function optimization

470 Views Asked by At

I found my self quite often parsing values from the so called Name Value Lists in JavaScript.

I used a self made function which did the job pretty well, however I decided to experiment with the prototype property. It seems to work, however I find the second function "nvlSet" kind of "ugly".

Do you think it is?.. if so, how do you think it can turn into a more "elegant" way to do the job.

if(!String.prototype.nvlGet) {
    String.prototype.nvlGet = function(nme,def){
        return((rem0=new RegExp('(\\b|,)' + nme + '=([^\\b][^,]*)').exec(this)) ? rem0[2] : def);
    }
}
if(!String.prototype.nvlSet) {
    String.prototype.nvlSet = function(nme,val){
        var re0=new RegExp('(\\b' + nme + '=[^\\b][^,]*)');
        if(re0.test(this)) return(this.replace(re0,nme + "=" + val));
        re0.compile('(,' + nme + '=[^\\b][^,]*)');
        return(this.replace(re0,',' + nme + "=" + val));
    }
}

var lst='firstName=John,lastName=Smith,department=Sales';
alert(lst.nvlGet('firstName')); // John
alert(lst.nvlGet('surName','none')); // none
lst=lst.nvlSet('department','Research');
alert(lst.nvlGet('department','unknown')); // Research
alert(lst); // firstName=John,lastName=Smith,department=Research

Also, I would like to avoid the "double assignation" like in here:

lst=lst.nvlSet('department','Research');

To something like this:

lst.nvlSet('department','Research');

However I could not find a way to do it.

3

There are 3 best solutions below

2
On

Strings are immuatable in javascript. You cannot change the contents of the current string object - ever. That's why all string methods that operate on the string return a new string object. So, your desired structure of:

lst.nvlSet('department','Research');

where you want it to modify the current string object cannot be done.

You could make your own regular object that saves the state and then have methods that get or set that state like this:

function nvl(str) {
    this.data = {};
    if (str) {
        this.data = this.parse(str);
    }
}

nvl.prototype = {
    parse: function(str) {
        var result = {}, pieces;
        var items = str.split(",");
        for (var i = 0; i < items.length; i++) {
            pieces = items[i].split("=");
            result[pieces[0]] = pieces[1];
        }
        return(result);
    },
    get: function(key, defaultVal) {
        var val = this.data[key];
        if (val === undefined) {
            val = defaultVal;
        }
        return(val);
    },
    set: function(key, value) {
        this.data[key] = value;
    },
    serialize: function() {
        var arr = [];
        for (var i in this.data) {
            if (this.data.hasOwnProperty(i)) {
                arr.push(i + "=" + this.data[i]);
            }
        }
        return(arr.join(","));
    }
};

Working example: http://jsfiddle.net/jfriend00/3urJF/

2
On

How about this:

//add nvl as a method to String prototype
String.prototype.nvl = function(){

    //new prototype for the dictionary object that gets returned
    var proto = {

        //convert the object literal back into a nvl
        toNvl: function(){

            var str = [];
            for(var i in this){

                if( this.hasOwnProperty(i) ){
                    str.push(i+'='+this[i]);
                }

            }

            //return str.join(',');
            return str.join(',');
        }
    },
    //set the prototype of the object literal to our own
    dict = Object.create(proto);

    //convert the string into an object literal
    keys = this.split(',');

    keys.forEach(function(val, index, arr){
        arr = val.split('=');
        dict[arr[0]] = arr[1];
    });

    return dict;
}


var pop = 'color=blue,num=234'.nvl(); //convert the string to an object

pop.color = 'red'; //access object properties normally.

pop = pop.toNvl(); //convert back to nvl. reassignment is unfortunately necessary
1
On

What I would suggest is serializing and deserializing nvls into Objects. A fairly simple example is:

function deserialize(nvl) {
  var re = /(\w+)=(\w+)/g, matches, props = {};
  while (matches = re.exec(nvl)) {
    props[matches[1]] = matches[2];
  }
  return props;
}

function serialize(props) {
  var prop, nvl = [];
  for (prop in props) {
    if (props.hasOwnProperty(prop)) {
      nvl.push(prop + '=' + props[prop]);
    }
  }
  return nvl.join(',');
}

Now your example becomes:

var props = deserialize('firstName=John,lastName=Smith,department=Sales');
alert(props.firstName); // John
alert(props.surName); // undefined
props.department = 'Research';
alert(props.department); // Research
alert(serialize(props)); // firstName=John,lastName=Smith,department=Research