Get object property name as a string

122,563

Solution 1

Yes you can, with a little change.

function propName(prop, value){
   for(var i in prop) {
       if (prop[i] == value){
            return i;
       }
   }
   return false;
}

Now you can get the value like so:

 var pn = propName(person,person.first_name);
 // pn = "first_name";

Note I am not sure what it can be used for.

Other Note wont work very well with nested objects. but then again, see the first note.

Solution 2

I know a best practice that using Object.keys(your_object). It will parse to array property name for you. Example:

var person = { firstName: 'John', lastName: 'Cena', age: '30' };
var listPropertyNames = Object.keys(person); //["firstName", "lastName", "age"]

I hope this example is useful for you.

Solution 3

You can accomplish this by converting all object properties into functions which will return the their own names

var person = {};
person.firstname = 'Jack';
person.address = "123 Street";

function getPropertyName(obj, expression) {
    var res = {};
    Object.keys(obj).map(k => { res[k] = () => k; });
    return expression(res)();
}

let result = getPropertyName(person, o => o.address);
console.log(result); // Output: 'address'

Solution 4

If anyone's looking for a TypeScript version of MarsRobot's answer, try this:

function nameof<T>(obj: T, expression: (x: { [Property in keyof T]: () => string }) => () => string): string
{
    const res: { [Property in keyof T]: () => string } = {} as { [Property in keyof T]: () => string };

    Object.keys(obj).map(k => res[k as keyof T] = () => k);

    return expression(res)();
}

Usage:

const obj = { 
    property1: 'Jim',
    property2: 'Bloggs',
    property3: 'Bloggs',
    method: () => 'a string',
    child: { property4: 'child1' }
};

const test1 = nameof(obj, x => x.property1);
const test2 = nameof(obj, x => x.property2);
const test3 = nameof(obj, x => x.method);
const test4 = nameof(obj.child, x => x.property4);

console.log(test1);    // -> 'property1'
console.log(test2);    // -> 'property2'
console.log(test3);    // -> 'method'
console.log(test4);    // -> 'property4'

This version works even when objects have multiple properties with the same value (unlike some of the other answers above), and with editors like Visual Studio will provide intellisense for the property names when you get here: nameof(obj, x => x.

Solution 5

You can wrap your property in a function and then convert the function to a string and get the property out of it.

For example:

function getPropertyName(propertyFunction) {
    return /\.([^\.;]+);?\s*\}$/.exec(propertyFunction.toString())[1];
}

Then to use it:

var myObj = {
    myProperty: "testing"
};

getPropertyName(function() { myObj.myProperty; }); // myProperty

Beware that minifiers could break this.

Edit: I have created a compiler transform that works with babel and the typescript compiler (see ts-nameof). This is a much more reliable than doing something at runtime.

Share:
122,563

Related videos on Youtube

CLiFoS
Author by

CLiFoS

Updated on September 20, 2021

Comments

  • CLiFoS
    CLiFoS over 2 years

    Is it possible to get the object property name as a string

    person = {};
    person.first_name = 'Jack';
    person.last_name = 'Trades';
    person.address = {};
    person.address.street = 'Factory 1';
    person.address.country = 'USA';
    

    I'd like to use it like this:

    var pn = propName( person.address.country ); // should return 'country' or 'person.address.country'
    var pn = propName( person.first_name );      // should return 'first_name' or 'person.first_name'
    

    NOTE: this code is exactly what I'm looking for. I understand it sounds even stupid, but it's not.

    This is what I want to do with it.

    HTML

    person = {};
    person.id_first_name = 'Jack';
    person.id_last_name = 'Trades';
    person.address = {};
    person.address.id_address = 'Factory 1';
    person.address.id_country = 'USA';
    
    
    extPort.postMessage
    (
      {
        message : MSG_ACTION,
        propName( person.first_name ): person.first_name
      }
    };
    

    ----------------------ANSWER-----------------------

    Got it thanks to ibu. He pointed the right way and I used a recursive function

    var res = '';
    
    function propName(prop, value) {
        for (var i in prop) {
            if (typeof prop[i] == 'object') {
                if (propName(prop[i], value)) {
                    return res;
                }
            } else {
                if (prop[i] == value) {
                    res = i;
                    return res;
                }
            }
        }
        return undefined;
    }
    
    var pn = propName(person, person.first_name); // returns 'first_name'
    var pn = propName(person, person.address.country); // returns 'country'
    

    DEMO: http://jsbin.com/iyabal/1/edit

    • RonaldBarzell
      RonaldBarzell over 11 years
      I'm confused... why do you want the property name to return the same thing you fed it? You already know the property name then... If you're looking for a way to iterate through properties, you can use the bracket notation and loop through the keys, as properties are also hash indices
    • Šime Vidas
      Šime Vidas over 11 years
      You need to also pass a reference to the object into the function.
    • I Hate Lazy
      I Hate Lazy over 11 years
      Not automatically. The string referenced by country property doesn't know anything about the address object, and the object referenced by the address property doesn't know anything about the person object.
    • CLiFoS
      CLiFoS over 11 years
      I understand this can be confusing, but that is exactly what I need. I need the property name as a string tough
    • Christophe
      Christophe over 11 years
      so you actually mean var pn = propName("USA");
    • Šime Vidas
      Šime Vidas over 11 years
      I'd love to help, but jsFiddle is currently unresponsive -.-
    • CLiFoS
      CLiFoS over 11 years
      no. the code I posted is what I need. basically, the prop name is the ID of the page element and I want to get it to use it.
    • I Hate Lazy
      I Hate Lazy over 11 years
      You need to explicitly pass them as separate values.
    • Jason
      Jason over 11 years
      You want to use the ID to get the prop, or the prop to get the ID?
    • Jason
      Jason over 11 years
      @Šime CodePen.io is better than jsFiddle anyway ;)
    • Christophe
      Christophe over 11 years
      You really need to clarify your question, maybe add the html sample. Look at the answers, 4 people have 4 different interpretations!!!
    • Jason L.
      Jason L. over 11 years
      Your code sample won't work as you're actually just passing the value of that property, not some reference to the property. Your first example would pass 'USA' to the function which is not useful for your desired result.
    • Aerik
      Aerik over 11 years
      Do you want to do this just because you like the coding style, or are you working wtih some existing unchangeable code that you need to use this way? What are your constraints?
    • Scott Sauyet
      Scott Sauyet over 11 years
      And jsbin.com/iyabal/2/edit shows the flaw with this approach.
    • Christophe
      Christophe over 11 years
      -1 Sorry, your code is really a bad practice. See this example: jsbin.com/iyabal/4/edit ... and en.wikipedia.org/wiki/Nestor_Burma as a reference ;-)
    • CLiFoS
      CLiFoS over 11 years
      yes, you are both right and I have doped this line of thinking. I'm sending an array as a parameter now, and it's working fine. thanks anyway.
    • Nic
      Nic about 9 years
    • RationalDev likes GoFundMonica
      RationalDev likes GoFundMonica almost 8 years
      This would be useful instead of passing strings around representing a object property name. You could then have static checking, refactoring or mangling.
    • Alain DENIS
      Alain DENIS about 7 years
    • Alain DENIS
      Alain DENIS about 7 years
      automatic name property for a created object you could have a look at that example.. ;)
    • Caltor
      Caltor over 4 years
      Can you delete your answer out of the question please. If you want to answer your own question post an actual answer below so others can vote on it.
    • Chris
      Chris over 2 years
      Tell me you want to use typescript without telling me you want to use typescript.
  • Sampson
    Sampson over 11 years
    This assumes that no two properties will have the same value in an object.
  • CLiFoS
    CLiFoS over 11 years
    your function returns 'first_name' if you pass person.first_name but if you use person.address.street returns false. maybe using it recursively?
  • Jason Sperske
    Jason Sperske over 11 years
    I was fascinated by this answer so I started hacking away at it to try and find a cleaner approach. here is what I've come up with so far, what do you think: jsfiddle.net/y4Y8p/17
  • David Hellsing
    David Hellsing over 11 years
    @JasonSperske nice, but it’s not recursive so it only works 3 levels deep: jsfiddle.net/y4Y8p/18
  • Jason Sperske
    Jason Sperske over 11 years
    jsfiddle.net/y4Y8p/22 try it now :) There are still larger problems, like it takes all values and casts them to strings, but this is a fun bit of code to play with
  • Vladislav
    Vladislav over 5 years
    It is the best solution!
  • Moha the almighty camel
    Moha the almighty camel about 5 years
    @Please_Dont_Bully_Me_SO_Lords, Hence the sentence: "my properties are functions that when called return the value of the property"
  • Moha the almighty camel
    Moha the almighty camel about 5 years
    and that's why I made it clear in my answer: 1- I am taking a different approach, 2- my properties are functions, 3- I have a note about how you should update the value of a property. By no means I am suggesting that this is the best approach, I am just proposing a way to do what OP wants to do. In his example it is a string because he is using plain attributes, in my approach I am wrapping them in functions. OP can use my answer to add wrapper around his attributes. My attributes are functions syntactically, yes. but, semantically, my attributes are the result of the function call,
  • Moha the almighty camel
    Moha the almighty camel about 5 years
    @Please_Dont_Bully_Me_SO_Lords, if you see anyway this answer can be improved, please be my guest. Thank you.
  • Florian Leitgeb
    Florian Leitgeb over 4 years
    And how do you get a specific key?
  • Maximilian Fixl
    Maximilian Fixl over 4 years
    Why shoult Object.keys return a specific key? The point from that question was, to get the key of an object as a string!? Or not? I‘m confused now...
  • Florian Leitgeb
    Florian Leitgeb over 4 years
    Yes, but you iterate over ALL keys. There is no chance getting a specific property name with your solution.
  • Maximilian Fixl
    Maximilian Fixl over 4 years
    Ah, I got it! No, my solution is only for all keys, you‘re right. I misunderstood the question.
  • saygley
    saygley almost 4 years
    If you see warning about "no return value"; here is the modified version: Object.keys(obj).map(k => { res[k] = () => k; return k;});
  • tno2007
    tno2007 almost 4 years
    Do you have a simple example how to use this method?
  • MadSkunk
    MadSkunk about 3 years
    FYI I've added a TypeScript version below if anyone's looking for one.
  • SMUsamaShah
    SMUsamaShah almost 3 years
    Why does even this work console.log(propName({}).first_name);?
  • SMUsamaShah
    SMUsamaShah almost 3 years
    This fails when properties have same value.
  • Digital Alpha
    Digital Alpha over 2 years
    this will give a wrong result in case the value of 2 keys are the same. ex: person = {old: 25, name:'John', age: 25}; propName(person, person.age); // return "old"
  • Digital Alpha
    Digital Alpha over 2 years
    this does not answer the question, as it will return an array of the keys. the answer should return one string value
  • Keslavi
    Keslavi about 2 years
    smh... everything triet said but add .join()
  • Luminous
    Luminous about 2 years
    To get rid of the "No index signature with a parameter of type ...." error, you need to add as keyof T to res[k]. It would be res[k as keyof T]. Suggested edit queue is full else I'd add this to the answer myself.