简体   繁体   中英

Javascript object: How to return property using value?

Given a Javascript object, I wonder whether there is a way to use value to return the corresponding property? I understand properties have to be unique, but values can duplicate. So perhaps a way to use value to return the first matching property?

var x = { a: 1, b: 2, c: 3, d: 4, e: 4 };

Want to use value 4 to access property d .

UPDATE : Thanks for the helpful responses. I just realized my question may not be a good one, as object (from Javascript) or hash (from Ruby) is really an unordered list, so asking for the "first matching" is not quite sound.

So perhaps a way to use value to return the first matching property?

You're into new territory there: Object properties have only had a defined order since ES2015 , and then only in relation to certain operations (a change in ES2020 makes the order relevant even to older operations that used to be exempt, in most cases) .

In this case, since those properties don't fit the definition of an array index, and they're all "own" properties (not inherited), they'll be in order based on when they were created . In an object literal (like the one in your question), properties are created in source code order , and so the a property is the first and the e property is the last.

But again, this order is only applied by certain operations. Neither for-in nor Object.keys , for instance, is guaranteed to follow this order. (see above)

But Object.getOwnPropertyNames is. So to find the first matching property, we can use Object.getOwnPropertyNames to get an array, and then take the first property whose value matches the target ( 4 ):

 function getFirstMatching(obj, value) { let result; Object.getOwnPropertyNames(obj).some(key => { if (obj[key] === value) { result = key; return true; // Stops the loop } }); return result; } const x = {a: 1, b: 2, c: 3, d: 4, e: 4}; console.log(getFirstMatching(x, 4)); // d

Notice that I used some other ES2015 features in there ( let , const , an arrow function). Since property order can't be shimmed/polyfilled, you can't rely on it in a non-ES2015 environment, so...

Please note the caveats on that:

  1. Requires a JavaScript engine that correctly supports ES2015 property order (cannot reliably be polyfilled/shimmed).
  2. Property order is only respected by certain operations ( getOwnPropertynames is one of them).
  3. Property names that look like array indexes are not kept in creation order (they're kept in numeric order, prior to other properties).
  4. Inherited properties show up after own properties.

The caveats matter. For instance, here we get e , not d :

 function getFirstMatching(obj, value) { let result; Object.getOwnPropertyNames(obj).some(key => { if (obj[key] === value) { result = key; return true; // Stops the loop } }); return result; } // Note that now e is first const x = {a: 1, b: 2, c: 3, e: 4, d: 4}; console.log(getFirstMatching(x, 4)); // e

Here we get q :

 function getFirstMatching(obj, value) { var result; Object.getOwnPropertyNames(obj).some(key => { if (obj[key] === value) { result = key; return true; // Stops the loop } }); return result; } // Note that now e is first const x = {i: 1, j: 2, k: 3, q: 4}; const y = {a: 1, b: 2, c: 3, d: 4, e: 4}; for (let key in y) { x[key] = y[key]; } console.log(getFirstMatching(x, 4)); // q

Try this:

function firstPropertyWithGivenValue(value, object){
   for(var key in object) {
     if(object[key] === value) return key;
   }
   return false;
}

firstPropertyWithGivenValue(4,x);

One option is looping over the object. Use break to break the loop at first match.

 var x = {a:1, b:2, c:3, d:4, e:4}, match; for(var i in x){ if(x[i] == 4){ match = i; break; } } console.log(match);

This is a slight modification of @wscourge's answer to ensure that the "first" property in lexicographic order is returned, without requiring ES2015.

It also allows customizing the "property order", if one should so desire.

function firstPropertyWithGivenValue(value, object) {
   var ret = undefined; 
   for (var key in object) {
       // To ignore inherited properties:
       // if (object.hasOwnProperty(key)) {
       if (object[key] == value) {
           if ((undefined === ret) || (key < ret)) {
               ret = key;
           }
       }
       // }
   }
   return ret;

}

This will return undefined if the property is not found, otherwise it will return the "first" property (remember that d comes before e , but eg key15 will come before key7 , which might not be what one expects).

You will have to loop over object to get the key whose value is matching.

Following is a generic function:

Logic:

  • Stringify the object and check if value exists in string. This will ensure you not looping if value is not there.
  • If exists, loop over keys of given object.
  • Check if current value is object. If yes, call self and search in the lower level. Since Object and Array both are of type object , you can use it as common logic.
  • If value is not an object, match it directly and return key.

Code

 function searchValueInObj(obj, searchValue){ if(!isAvailable(obj, searchValue)) return; for(var k in obj){ if(!obj.hasOwnProperty(k)) continue; let o = obj[k]; if(typeof(o) === "object" && isAvailable(o, searchValue)){ return searchValueInObj(o, searchValue) } else if(o === searchValue) return k; } } function isAvailable(obj, searchVal){ return JSON.stringify(obj).indexOf(searchVal) > -1 } var x = {a:1, b:2, c:3, d:4, e:4, f: { g: 5, h:{i:6, j:{k: 7, l:4}}}}; console.log(searchValueInObj(x,4)); console.log(searchValueInObj(x,5)); console.log(searchValueInObj(x,7));

for (let item in x) {
    if (x[item] === 4){
        return item
    }
}

This will return d in your cause, but with a pretty major flaw, if the order of the object were to change, then you might end up with a different result.

var x = {a:4, b:2, c:3, d:4, e:4};

Using the above piece of code on this object would result in a being returned instead of d . So while it is possible, it's probably not best to find a property based on the value inside the object.

In what situation are you using this? There may be a more reliable way to get the result you're looking for.

 var x = {a:1, b:2, c:3, d:4, e:4}; var re=4; for(var a in x) { if(x[a]==re){ console.log(a); break; } }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM