web-dev-qa-db-ja.com

オブジェクトプロパティ名を文字列として取得

オブジェクトのプロパティ名を文字列として取得することは可能ですか?

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'

[〜#〜] note [〜#〜]:このコードはまさに私が探しているものです。愚かにも聞こえますが、そうではありません。

これが私がやりたいことです。

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 [〜#〜]-----------------------

イブのおかげでそれを得た。彼は正しい方法を指摘し、再帰関数を使用しました

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

44
CLiFoS

はい、できます。少し変更してください。

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
Ibu

Object.keys(your_object) を使用するベストプラクティスを知っています。配列プロパティ名に解析されます。例:

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

この例がお役に立てば幸いです。

21
Triet Nguyen

プロパティで関数をラップし、関数を文字列に変換して、プロパティを取得できます。

例えば:

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

それを使用するには:

var myObj = {
    myProperty: "testing"
};

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

ミニファイナーがこれを破ることができることに注意してください。

編集:babelとTypeScriptコンパイラで動作するコンパイラトランスフォームを作成しました( ts-nameof を参照)。これは、実行時に何かをするよりもはるかに信頼性があります。

8
David Sherret

これは、すべてのオブジェクトプロパティを独自の名前を返す関数に変換することで実現できます。

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'
7
artemnih

プロキシを使用する:

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

ES6で@David Sherretの回答をフォローアップすると、非常に簡単になります。

propName = f => /\.([^\.;]+);?\s*\}$/.exec(f.toString())[1]
let prop = propName(() => {obj.name}); // myProperty
1
Nimrod

いいえ、できません。

これを想像してください:

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

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

プロパティ名への参照は、そのプロセスで単に失われます。

1
Scott Sauyet

私はパーティーに遅れていますが、まったく異なるアプローチを取りました。そのため、私は自分のアプローチを取り入れて、コミュニティが何を考えているかを見ていきます。

Function.prototype.name を使用して、必要な処理を行いました。私のプロパティは、呼び出されたときにプロパティの値を返す関数であり、.nameを使用してプロパティの名前(関数)を取得できます

以下に例を示します。

person = {
    firstName(){
        return 'John';
    },
    address(){
        return '123 street'
    }
}

person.firstName.name // 'firstName'
person.address.name // 'address'

注:
この場合、実行時にプロパティの値(firstnameなど)を簡単に変更することはできません。関数を作成する必要があり(この場合、.nameは匿名になります)、この関数は新しい値を返す新しい名前付き関数を返します。

// note the () at the end     
person.firstName = new Function('', 'return function firstName(){return "johny"}')(); 
person.firstName.name ; // 'firstName' 
person.firstName(); // 'johny'

私も同じ状況です。

Lodash または nderScore ライブラリを使用して実行する方法を以下に示します。値が一意であるという制限があります。

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 )
0
Amit Bhagat

私は1つのライナーが好きです、ここに一般的な解決策があります:

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

propName(person, person.age)
0
Nimrod

オブジェクトのネームスペースメソッドを作成できます。このメソッドは、value_namespaceの2つのプロパティを保持する代わりに、文字列がオブジェクトになるようにオブジェクトを変更する必要があります。

デモ: 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);
0
David Hellsing