Get object property name as a string
JavascriptStringObjectPropertiesJavascript Problem Overview
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'
Javascript Solutions
Solution 1 - Javascript
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 2 - Javascript
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 3 - Javascript
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.
Solution 4 - Javascript
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] = () => 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 - Javascript
Using Proxy:
var propName = ( obj ) => new Proxy(obj, {
get(_, key) {
return key;
}
});
var person = {};
person.first_name = 'Jack';
person.last_name = 'Trades';
person.address = {};
person.address.street = 'Factory 1';
person.address.country = 'USA';
console.log(propName(person).first_name);
console.log(propName(person.address).country);
Solution 6 - Javascript
I like one liners, here's a generic solution:
const propName = (obj,type) => Object.keys(obj).find(key => obj[key] === type)
propName(person, person.age)
Solution 7 - Javascript
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 8 - Javascript
I use the following in TypeScript. This way retains type-information and disallows selecting non-existing property keys.
export function getPropertyName<T extends object>(obj: T, selector: (x: Record<keyof T, keyof T>) => keyof T): keyof T {
const keyRecord = Object.keys(obj).reduce((res, key) => {
const typedKey = key as keyof T
res[typedKey] = typedKey
return res
}, {} as Record<keyof T, keyof T>)
return selector(keyRecord)
}
const obj = {
name: 'test',
address: {
street: 'test',
}
}
console.log(getPropertyName(obj, (x) => x.name)) // name
console.log(getPropertyName(obj.address, (x) => x.street)) // street
Solution 9 - Javascript
Following up on @David Sherret's answer with ES6 it can be made super simple:
propName = f => /\.([^\.;]+);?\s*\}$/.exec(f.toString())[1]
let prop = propName(() => {obj.name}); // myProperty
Solution 10 - Javascript
I prefer it clean and simple like this:
var obj = {
sessionId: 123,
branchId: 456,
seasonId: 789
};
var keys = Object.keys(obj);
for (var i in keys) {
console.log(keys[i]); //output of keys as string
}
Solution 11 - Javascript
You could create a namespacing method for the object. The method will need to mutate the object so that the strings becomes an object instead to hold two properties, a value
and a _namespace
.
DEMO: http://jsfiddle.net/y4Y8p/1/
var namespace = function(root, name) {
root._namespace = name;
function ns(obj) {
for( var i in obj ) {
var a = obj._namespace.split('.')
if ( a.length ) {
a.push(i);
}
if( typeof obj[i] == 'object' ) {
obj[i]._namespace = a.join('.');
ns(obj[i]);
return;
}
if( typeof obj[i] == 'string' ) {
var str = obj[i].toString();
obj[i] = {
_namespace: a.join('.'),
value: str
};
}
}
}
ns(root);
};
namespace(person, 'person');
console.log(person.address.street._namespace) // person.address.street
console.log(person.address.street.value) // 'Factory 1'
So now you can do:
var o = { message: MSG_ACTION };
o[ person.first_name._namespace ] = person.first_name.value;
extPort.postMessage(o);
Solution 12 - Javascript
I am in same situation.
Here is thy way to get it done using Lodash or UnderScore library, with one limitation of value to be unique:
var myObject = {
'a': 1,
'b': 2,
'c': 3
}
_.findKey(myObject, function( curValue ) { return myObject.a === curValue });
Plain JavaScript
function getPropAsString( source, value ){
var keys = Object.keys( source );
var curIndex,
total,
foundKey;
for(curIndex = 0, total = keys.length; curIndex < total; curIndex++){
var curKey = keys[ curIndex ];
if ( source[ curKey ] === value ){
foundKey = curKey;
break;
}
}
return foundKey;
}
var myObject = {
'a': 1,
'b': 2,
'c': 3
}
getPropAsString( myObject, myObject.a )
But, I would prefer to fix the code as solution. An example:
var myObject = {
'a': {key:'a', value:1},
'b': {key:'b', value:2},
'c': {key:'c', value:3}
}
console.log( myObject.a.key )
Solution 13 - Javascript
I am late to the party but I took a completely different approach, so I will throw in my approach and see what the community thinks.
I used Function.prototype.name
to do what I want.
my properties are functions that when called return the value of the property, and I can get the name of the property (which is a function) using .name
Here is an example:
person = {
firstName(){
return 'John';
},
address(){
return '123 street'
}
}
person.firstName.name // 'firstName'
person.address.name // 'address'
Note:
you can't easily change the value of a property (e.g firstname) at run time in this case.
you would need to create a function (.name
would be anonymous in this case) and this function would return a new named function which return the new value:
// note the () at the end
person.firstName = new Function('', 'return function firstName(){return "johny"}')();
person.firstName.name ; // 'firstName'
person.firstName(); // 'johny'
Solution 14 - Javascript
No, it's not possible.
Imagine this:
person.age = 42;
person.favoriteNumber = 42;
var pn = propName(person.age)
// == propName(42)
// == propName(person.favoriteNumber);
The reference to the property name is simply lost in that process.