是否可以将对象属性名称作为字符串
person = {};
person.first_name = 'Jack';
person.last_name = 'Trades';
person.address = {};
person.address.street = 'Factory 1';
person.address.country = 'USA';
我想像这样使用它:
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'
注意:这段代码正是我正在寻找的。我明白这听起来很愚蠢,但事实并非如此。
这就是我想用它做的事。
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 ----------------- ------
感谢ibu。他指出了正确的方法,我使用了一个递归函数
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'
答案 0 :(得分:19)
答案 1 :(得分:8)
您可以将属性包装在一个函数中,然后将该函数转换为字符串并从中获取该属性。
例如:
function getPropertyName(propertyFunction) {
return /\.([^\.;]+);?\s*\}$/.exec(propertyFunction.toString())[1];
}
然后使用它:
var myObj = {
myProperty: "testing"
};
getPropertyName(function() { myObj.myProperty; }); // myProperty
请注意,缩小器可以打破这个。
编辑我创建了一个适用于babel和typescript编译器的编译器转换(请参阅ts-nameof)。这比在运行时做某事要可靠得多。
答案 2 :(得分:5)
您可以通过将所有对象属性转换为将返回其自己名称的函数来实现此目的
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'
答案 3 :(得分:3)
如果有人正在寻找 MarsRobot 答案的 TypeScript 版本,请尝试以下操作:
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)();
}
用法:
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'
即使对象具有多个具有相同值的属性(与上面的其他一些答案不同),此版本也能正常工作,并且使用 Visual Studio 等编辑器,当您到达此处时,将为属性名称提供智能感知:nameof(obj, x => x.
< /p>
答案 4 :(得分:2)
是的,你可以,稍作改动。
function propName(prop, value){
for(var i in prop) {
if (prop[i] == value){
return i;
}
}
return false;
}
现在你可以得到这样的值:
var pn = propName(person,person.first_name);
// pn = "first_name";
注意我不确定它可以用于什么。
其他注意事项对嵌套对象无效。但话又说回来,请看第一张纸条。
答案 5 :(得分:1)
不,这是不可能的。
想象一下:
person.age = 42;
person.favoriteNumber = 42;
var pn = propName(person.age)
// == propName(42)
// == propName(person.favoriteNumber);
在该过程中,对属性名称的引用就会丢失。
答案 6 :(得分:1)
按照@David Sherret对ES6的回答,它可以变得非常简单:
(<*>)
答案 7 :(得分:0)
您可以为对象创建命名空间方法。该方法需要改变对象,以便字符串成为一个对象,而不是保留两个属性,value
和_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'
现在你可以这样做:
var o = { message: MSG_ACTION };
o[ person.first_name._namespace ] = person.first_name.value;
extPort.postMessage(o);
答案 8 :(得分:0)
我情况相同。
以下是使用Lodash或UnderScore库完成此操作的方法,其中一个值限制是唯一的:
var myObject = {
'a': 1,
'b': 2,
'c': 3
}
_.findKey(myObject, function( curValue ) { return myObject.a === curValue });
普通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 )
但是,我更愿意将代码修复为解决方案。一个例子:
var myObject = {
'a': {key:'a', value:1},
'b': {key:'b', value:2},
'c': {key:'c', value:3}
}
console.log( myObject.a.key )
答案 9 :(得分:0)
我更喜欢这样简洁明了:
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
}
答案 10 :(得分:0)
我参加晚会很晚,但是我采取了完全不同的方法,因此我会提出自己的方法,并看看社区的想法。
我用Function.prototype.name
做我想做的事。
我的属性是调用时返回属性值的函数,我可以使用.name
这里是一个例子:
person = {
firstName(){
return 'John';
},
address(){
return '123 street'
}
}
person.firstName.name // 'firstName'
person.address.name // 'address'
注意:
在这种情况下,您将无法在运行时轻松更改属性(例如名字)的值。
您将需要创建一个函数(在这种情况下,.name
将是匿名的),并且该函数将返回一个新的命名函数,该函数将返回新值:
// note the () at the end
person.firstName = new Function('', 'return function firstName(){return "johny"}')();
person.firstName.name ; // 'firstName'
person.firstName(); // 'johny'
答案 11 :(得分:0)
使用代理:
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);
答案 12 :(得分:0)
我喜欢一个内胆,这是一个通用的解决方案:
const propName = (obj,type) => Object.keys(obj).find(key => obj[key] === type)
propName(person, person.age)
答案 13 :(得分:0)
我在TypeScript中使用以下内容。这种方式保留了类型信息,并且不允许选择不存在的属性键。
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)
}