86

是否可以将对象属性名称作为字符串获取

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
  }
};

----------------------答案-----------

感谢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'

演示:http: //jsbin.com/iyabal/1/edit

4

14 回答 14

39

我知道使用Object.keys(your_object)的最佳实践。它将为您解析为数组属性名称。例子:

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

我希望这个例子对你有用。

于 2016-06-09T08:33:51.517 回答
21

您可以通过将所有对象属性转换为将返回它们自己的名称的函数来完成此操作

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'
于 2017-12-08T04:27:04.903 回答
13

您可以将属性包装在一个函数中,然后将该函数转换为字符串并从中获取该属性。

例如:

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

然后使用它:

var myObj = {
    myProperty: "testing"
};

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

请注意,缩小器可能会破坏这一点。

编辑:我创建了一个可与 babel 和 typescript 编译器一起使用的编译器转换(请参阅ts-nameof)。这比在运行时做某事要可靠得多。

于 2015-09-12T18:38:03.617 回答
9

如果有人在寻找 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.

于 2021-03-27T23:05:58.867 回答
8

我喜欢一个衬垫,这是一个通用的解决方案:

const propName = (obj,type) => Object.keys(obj).find(key => obj[key] === type)

propName(person, person.age)
于 2019-09-01T15:03:33.220 回答
7

是的,您可以,只需稍作改动。

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";

注意我不确定它可以用来做什么。

其他注释不适用于嵌套对象。但话又说回来,请参阅第一个注释。

于 2012-11-28T18:38:21.687 回答
7

使用代理:

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);

于 2019-06-05T13:38:34.007 回答
4

我在 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)
}

const obj = {
  name: 'test',
  address: {
    street: 'test',
  }
}

console.log(getPropertyName(obj, (x) => x.name)) // name
console.log(getPropertyName(obj.address, (x) => x.street)) // street
于 2019-12-27T08:57:21.597 回答
2

跟进@David Sherret 对 ES6 的回答,它可以变得非常简单:

propName = f => /\.([^\.;]+);?\s*\}$/.exec(f.toString())[1]
let prop = propName(() => {obj.name}); // myProperty
于 2019-01-13T10:11:26.307 回答
1

我更喜欢这样干净简单:

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
}
于 2018-11-05T15:52:37.640 回答
0

不,这是不可能的。

想象一下:

person.age = 42;
person.favoriteNumber = 42;

var pn = propName(person.age)
// == propName(42)
// == propName(person.favoriteNumber);

在该过程中,对属性名称的引用完全丢失了。

于 2012-11-28T18:40:12.310 回答
0

您可以为对象创建命名空间方法。该方法将需要改变对象,以便字符串成为一个对象,而不是保存两个属性, avalue和 a _namespace

演示: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);
于 2012-11-28T19:17:48.337 回答
0

我也有同样的情况。

这是您使用LodashUnderScore库完成它的方法,其中一个限制是唯一的值:

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 )
于 2017-07-07T11:20:32.717 回答
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'
于 2019-01-05T20:26:51.767 回答