【问题标题】:How to get the last key of object which has a value如何获取具有值的对象的最后一个键
【发布时间】:2017-07-10 10:27:41
【问题描述】:

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

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'

【问题讨论】:

  • 你如何定义“last”,那些是对象的字段。
  • @user3142695 你的意思是你的问题只针对这个特定的对象吗?
  • "last" 对对象属性没有意义。订单不相关
  • 对象的属性没有内在的顺序,所以你的问题实际上没有意义。没有“最后一个”键。浏览器通常按字母顺序列出属性,例如在开发者控制台中,但这只是为了方便开发者。数组是具有内在顺序的结构。
  • 我投票决定将此问题作为离题结束,因为没有更多信息,无法解决。

标签: javascript


【解决方案1】:

对象属性 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 构造函数接受一个迭代来创建一个Map。数组数组构造了一个Map,其中包含子数组的键和值对。因此,以下Map 被创建并存储到obj

+----------+-----------+
| Key      | Value     |
+----------+-----------+
| "first"  | "foo"     |
| "second" | "bar"     |
| "third"  | undefined |
| "fourth" | undefined |
+----------+-----------+

然后,Array.from(obj.keys()) 行从 Map 的键(firstsecondthirdfourth)创建一个数组。然后它使用Array.prototype.reduce 推导出具有定义值的最后一个键。

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


1需要注意的是,在 ES2015 中,有一些方法选择确实实际上保证按插入顺序返回键。这些包括Object.assignObject.definePropertiesObject.getOwnPropertyNamesObject.getOwnPropertySymbolsReflect.ownKeys。您可以依赖这些,而不是使用Map

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

【讨论】:

  • they're just an unordered collection of properties。实际上我已经通过引入i 计数变量来订购它们。我希望有人像 T.J.克劳德谈到了这个案子。
  • @Kinduser:如果同时需要 order 和 key-lookup,那么 Andrew 所示的 Map 正是这样做的正确方法。对对象执行此操作是错误的,因为对象属性顺序不仅仅是插入顺序:名称为规范定义的整数索引的属性位于第一位。 (当你进入继承时,它变得更加复杂。)
【解决方案2】:

非常棘手,通过对象的迭代不一定保证顺序。 ES2015 provides several methods 按照创建顺序遍历符号\字符串类型键。

假设 最后一个有值的键是在对象中定义的最后一个具有真实值的条目:

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。如果需要任何未定义的值,请使用val => val !== undefined 作为过滤回调.
  3. 获取过滤后数组中的最后一项(如果所有值都是假的,将返回 undefined)。

【讨论】:

  • @user3142695: Reuven 的.filter(key => !!obj[key]) 将过滤掉所有 虚假值(包括0"" 等),而不仅仅是undefined,所以如果这不是你想要的,你必须调整它。以上还创建了两个不必要的临时数组(但这不太重要)。
  • 有人提到他寻找一个有值的键。 @user3142695 没有提到他寻找一个未定义的值,无论如何,我同意这可能是根据示例的用例。感谢您的评论,编辑了答案。
【解决方案3】:

如果您需要获取“带有值的最后一个属性”,则说明您使用了错误的数据结构。一个对象就是不合适。您想使用数组或Map。我可能会使用Mapas 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 specification1,按数字顺序排列,然后是任何其他属性, 按照它们添加到对象的顺序。

你明白为什么一个对象是错误的结构:整数索引优先于其他属性,所以给定:

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;
}

注意最后的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-02
    相关资源
    最近更新 更多