我需要获取具有值的对象的最后一个键。所以,如果这是对象......
const obj = { first: 'value', second: 'something', third: undefined, fourth: undefined }
......我需要second
obj = { first: 'value', second: 'something', third: 'else', fourth: undefined }
// result should be: 'third'
obj = { any: 'value', other: 'something', thing: undefined, bla: undefined }
// result should be: 'other'
答案 0 :(得分:3)
对象属性 do 具有与插入顺序不同的特定顺序,在这种情况下,T.J. Crowder描述的顺序并不真正有用。 This Stack Overflow问题是关于这个主题的一个很好的阅读,我建议阅读比第一个答案更进一步。
因此,不要依赖无法保证订购 1 的对象,而是使用做保证订单的东西。您可以使用Map
之类的东西,类似于具有键/值对的对象,但对是。例如:
const obj = new Map([
["first", "foo"],
["second", "bar"],
["third", undefined],
["fourth", undefined]
]);
const result = Array.from(obj.keys()).reduce((lastKey, currKey) => obj.get(currKey) !== undefined ? currKey : lastKey);
console.log(result);
Map
构造函数接受一个iterable来创建一个Map
。数组数组构造一个Map
,其中包含子数组的键和值对。因此,创建了以下Map
并将其存储到obj
:
+----------+-----------+
| Key | Value |
+----------+-----------+
| "first" | "foo" |
| "second" | "bar" |
| "third" | undefined |
| "fourth" | undefined |
+----------+-----------+
然后,行Array.from(obj.keys())
根据Map
first
,second
,third
和{{1}的键创建一个数组}。然后,它使用Array.prototype.reduce
推导出具有已定义值的最后一个密钥。
fourth
回调使用reduce
,它是具有定义值的累加器/最后一个密钥,lastKey
是正在处理的当前密钥。然后检查obj.get(currKey)
是否未定义。如果未定义,则返回并分配给累加器。这将遍历整个数组,最终值(累加器)将返回currKey
。结果是具有定义值的最后一个键。 2
1 应该注意的是,在ES2015中,有一些 实际上保证在插入顺序中返回密钥的方法。其中包括result
,Object.assign
,Object.defineProperties
,Object.getOwnPropertyNames
和Object.getOwnPropertySymbols
。您可以依赖这些,而不是使用Reflect.ownKeys
。
2 还有很多其他方法可以获得最后一个密钥。您可以像Reuven Chacha那样过滤数组并对其进行切片。我认为减少它更具描述性,但其他一些方法在操作中更为直接。
答案 1 :(得分:3)
如果您需要获取“带有值的最后一个属性”,那么您使用的是错误的数据结构。一个物体不太适合。您想使用数组或Map
。我可能会使用Map
as shown by Andrew Li,因为它定义了有用的顺序以及基于密钥的查找。
如果你坚持使用一个对象:Object properties do have an order,自ES2015起(又名“ES6”)。该命令仅由某些操作强制执行;由for-in
或Object.keys
强制执行 。大多数其他操作强制执行 ,包括Object.getOwnPropertyNames
(ES2015),ES2017规范中即将发布的Object.values
,以及(有趣的)JSON.stringify
。
但是,订单对您来说不太可能有用。假设我们只讨论名称不是符号的“自己”属性,则顺序为:任何属性为“整数索引”as defined by the specification 1 ,按数字顺序排列,后跟任何其他属性,按照它们添加到对象的顺序。
你知道为什么一个对象是错误的结构:整数索引优先于其他属性,所以给定:
const obj = { first: 'value', second: 'something', third: undefined, 42: 'value' };
...使用对象的顺序,我们会说最后一个值是'something'
,它应该是'value'
。使用Map
,您将得到正确的答案。
所以,我不建议使用此对象,但如果您坚持这样做,那么您可以在完全兼容的ES2015 + JavaScript引擎上执行此操作:
function test(testNumber, obj) {
const last = Object.getOwnPropertyNames(obj).reduce((currentValue, key) => {
const value = obj[key];
return typeof value === "undefined" ? currentValue : value;
}, undefined);
console.log(`Test #${testNumber}: '${last}'`);
}
// This says 'something' (value of `second`):
test(1, { first: 'value', second: 'something', third: undefined, fourth: undefined });
// This says 'else' (value of `third`):
test(2, { first: 'value', second: 'something', third: 'else', fourth: undefined });
// This says 'something' (value of `other`):
test(3, { any: 'value', other: 'something', thing: undefined, bla: undefined });
// BUT! This says 'something' (value of `second`), not 'value' (value of `42`)!
test(4, { first: 'value', second: 'something', third: undefined, 42: 'value' });
.as-console-wrapper {
max-height: 100% !important;
}
请注意最后的结果。
答案 2 :(得分:1)
非常棘手,通过对象迭代并不一定能保证顺序。 ES2015 provides several methods按照创建顺序迭代符号\字符串类型键。
假设具有值的最后一个键是在具有truthy值的对象中定义的最后一个条目:
function getLastKeyWithTruthyValue(obj) {
Object.getOwnPropertyNames(obj).filter(key => !!obj[key]).slice(-1)[0]
}
filter(Boolean)
可以是一种很酷的过滤方法,as described in this cool answer。如果需要不未定义的任何值,请使用{{1作为过滤器回调。