如何获取具有值的对象的最后一个键

时间:2017-02-21 00:16:38

标签: javascript

我需要获取具有值的对象的最后一个键。所以,如果这是对象......

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'

3 个答案:

答案 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 firstsecondthird和{{1}的键创建一个数组}。然后,它使用Array.prototype.reduce推导出具有已定义值的最后一个密钥。

fourth回调使用reduce,它是具有定义值的累加器/最后一个密钥,lastKey是正在处理的当前密钥。然后检查obj.get(currKey)是否未定义。如果未定义,则返回并分配给累加器。这将遍历整个数组,最终值(累加器)将返回currKey。结果是具有定义值的最后一个键。 2

1 应该注意的是,在ES2015中,有一些 实际上保证在插入顺序中返回密钥的方法。其中包括resultObject.assignObject.definePropertiesObject.getOwnPropertyNamesObject.getOwnPropertySymbols。您可以依赖这些,而不是使用Reflect.ownKeys

2 还有很多其他方法可以获得最后一个密钥。您可以像Reuven Chacha那样过滤数组并对其进行切片。我认为减少它更具描述性,但其他一些方法在操作中更为直接。

答案 1 :(得分:3)

如果您需要获取“带有值的最后一个属性”,那么您使用的是错误的数据结构。一个物体不太适合。您想使用数组或Map。我可能会使用Map as shown by Andrew Li,因为它定义了有用的顺序以及基于密钥的查找。

如果你坚持使用一个对象:Object properties do have an order,自ES2015起(又名“ES6”)。该命令仅由某些操作强制执行;由for-inObject.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]
}
  1. 以创建顺序获取属性名称数组(大多数现代浏览器都支持Object.getOwnPropertyNames,see browser compatibility
  2. 过滤掉虚假值(使用filter(Boolean)可以是一种很酷的过滤方法,as described in this cool answer。如果需要未定义的任何值,请使用{{1作为过滤器回调。
  3. 获取已过滤数组中的最后一项(如果所有值都是假的,将返回undefined)。