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:
- Requires a JavaScript engine that correctly supports ES2015 property order (cannot reliably be polyfilled/shimmed).
Property order is only respected by certain operations (getOwnPropertynames
is one of them).
- Property names that look like array indexes are not kept in creation order (they're kept in numeric order, prior to other properties).
- 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