3

I'm relatively new to JavaScript so please forgive me if this is silly/impossible, but I'm trying to standardize names of properties within a JavaScript object. For example, I have code such as

var object = {
    "firstName": "Joe",
    "MiddleName": "Roy",
    "last_name": "Fool"
}

I want to make a new object that has property names firstName, middleName, and lastName. Is there any way to search through these properties and see which ones are in violation? Otherwise, I could always just make a total copy but that would be quite inefficient. Thanks

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • "*I want to make a new object*" is always a total copy, what else did you have in mind? – Bergi Jun 27 '13 at 18:47
  • You don't know know which ones are in violation necessarily, correct? You're looking for some kind of linguistic parser? – oooyaya Jun 27 '13 at 18:48
  • 1
    This question answers how to iterate trought property names of an object: http://stackoverflow.com/questions/85992/how-do-i-enumerate-the-properties-of-a-javascript-object – Eric Beaulieu Jun 27 '13 at 18:51
  • exactly, a linguistic parser would be a good way to put it – ablackman93 Jun 27 '13 at 18:58
  • This fiddle would work for your example, but it would not change lastname to lastName http://jsfiddle.net/hAMWx/ but it's a start – Eric Beaulieu Jun 27 '13 at 19:12

3 Answers3

1

This might be going beyond what you're looking for, but it's pretty easy to convert your underscore-separated naming to camelcase; you can iterate over your object and produce a new object with the correct names:

var converter = /_(\w)/g, lowerFirst = /^(\w)/;
function convertName(name) {
  if (converter.test(name)) {
    name = name.toLowerCase().replace(converter, function ($0, $1) {
             return $1.toUpperCase();
           });
  } else {
    // correct a first letter being uppercase
    name = name.replace(lowerFirst, function ($0, $1){ return $1.toLowerCase(); });
  }

  return name;
}

var hasOwnProperty = Object.prototype.hasOwnProperty,
    toString = Object.prototype.toString;

function isPlainObject(obj) {
  return toString.call(obj) === '[object Object]';
}


function convertObject(obj) {
  var k, output = {};
  for(k in obj) {
    if (hasOwnProperty.call(obj, k)) {
      output[convertName(k)] = isPlainObject(obj[k]) ? convertObject(obj[k]) : obj[k];
    }
  }

  return output;
}

If the property names are already in camelcase, they won't be changed by the regexp.

bokonic
  • 1,751
  • 10
  • 12
  • 1
    This doesn't fix `convertName('MiddleName'); // "MiddleName"` – Paul S. Jun 27 '13 at 19:02
  • This wasn't in OPs example, but also you'll get `convertName('MIDDLE_NAME'); // "mIDDLENAME"` – Paul S. Jun 27 '13 at 19:06
  • tried to be a bit more robust by testing for underscore first; hard to write code too much beyond OP's examples since totally wrong camelcase input is hard/impossible to correct with a regexp – bokonic Jun 27 '13 at 19:10
  • The only formats I have coming in are upper case first letter, camel case, and subscript...I'm thinking that somehow I may be able to run the first letters of these properties through a lower-case parser after I take care of the subscript – ablackman93 Jun 27 '13 at 19:23
  • @ablackman93 if those are your only cases then `convertName` should work – bokonic Jun 27 '13 at 19:31
  • 1
    You seem to be missing a `)` from `if (converter.test(name) {` – Xotic750 Jun 27 '13 at 20:37
  • Hmm...I just realized that I need to make this recursive because I am dealing with attributes such as addresses which are in themselves objects that contain attributes (which must go by the same naming convention). I suppose I could just insert an if statement after the for(k in obj) to check if 'k' is an object and then call convertObject on 'k' itself? – ablackman93 Jun 27 '13 at 20:41
0

By your example, one quick way is to map values of properties to a second object with a dictionary to choose the property names, obtained by (for example) Object.getOwnPropertyNames

var object = {"firstName": "Joe", "MiddleName": "Roy", "last_name": "Fool"};

var p = Object.getOwnPropertyNames(object), // ["firstName", "MiddleName", "last_name"]
    dict = {
        'firstname': 'firstName',
        'first_name': 'firstName',
        'middlename': 'middleName',
        'middle_name': 'middleName',
        'lastname': 'lastName',
        'last_name': 'lastName'
    },
    o2 = {}, i;

for (i = 0; i < p.length; ++i) {
    o2[dict[p[i].toLowerCase()] || p[i]] = object[p[i]];
}

o2; // {firstName: "Joe", middleName: "Roy", lastName: "Fool"}
Paul S.
  • 64,864
  • 9
  • 122
  • 138
0

You could possibly do something like this.

The first replace can be used to replace any characters that you want to be markers for upper cased camel casing.

The second replace performs the camel casing on the letter that follows the marker.

The final replace makes sure that the first letter of the identifier is lower case.

standardiseProperties works on the object in place using the rules of camelCase. But you could just as well have it return the new object standardised.

If a name can not be used as it already exists, then the original name is used.

I didn't spend much time on this and there could well be optimisations, or you may wish to change the rules somewhat.

Javascript

function camelCase(string) {
    return string.replace(/[-+]/g, "_").replace(/_([\da-z])/gi, function (all, letter) {
        return letter.toUpperCase();
    }).replace(/^([A-Z])/, function (all, letter) {
        return letter.toLowerCase();
    });
}

function standardiseProperties(object) {
    var standardised = {},
        newName,
        i;

    for (i in object) {
        if (object.hasOwnProperty(i)) {
            newName = camelCase(i);
            if (standardised.hasOwnProperty(newName)) {
                standardised[i] = object[i];
            } else {
                standardised[newName] = object[i];
            }

            delete object[i];
        }
    }

    for (i in standardised) {
        object[i] = standardised[i];
    }
}

var object = {
    "firstName": "Joe",
    "MiddleName": "Roy",
    "last_name": "Fool"
};

console.log(object);
standardiseProperties(object);
console.log(object);

Output

Object {firstName: "Joe", MiddleName: "Roy", last_name: "Fool"}
Object {firstName: "Joe", middleName: "Roy", lastName: "Fool"} 

On jsfiddle

Xotic750
  • 22,914
  • 8
  • 57
  • 79