如果我有一个对象的引用:
var test = {};
可能(但不是立即)有嵌套对象,如:
{level1: {level2: {level3: "level3"}}};
在最深层嵌套的对象中测试密钥是否存在的最佳方法是什么?
alert(test.level1);
收益 undefined
,但 alert(test.level1.level2.level3);
失败 .
我现在正在做这样的事情:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
但我想知道是否有更好的方法 .
30 回答
如果您像字符串一样处理名称,则可以读取任何深度的对象属性:
't.level1.level2.level3'
.如果任何段为
undefined
,则返回undefined
.基于a previous comment,这是另一个版本,其中主要对象也无法定义:
如果您不想要
TypeError
,则必须一步一步地执行此操作,因为如果其中一个成员是null
或undefined
,并且您尝试访问某个成员,则会抛出异常 .您可以简单地
catch
异常,或者创建一个函数来测试多个级别的存在,如下所示:这是一个模式我picked up from Oliver Steele:
事实上,整篇文章讨论了如何在javascript中执行此操作 . 他习惯于使用上面的语法(一旦你习惯它就不难读)作为一个习语 .
更新
对于所有需要的嵌套属性,看起来像lodash has added
_.get
.https://lodash.com/docs#get
以前的答案
lodash用户可能喜欢lodash.contrib,其中有couple methods that mitigate this problem .
getPath
Signature:
_.getPath(obj:Object, ks:String|Array)
获取嵌套对象中任何深度的值,该值基于给定键所描述的路径 . 键可以作为数组或以点分隔的字符串给出 . 如果无法到达路径,则返回
undefined
.我已经完成了performance tests(感谢cdMinix添加lodash)对这个问题提出的一些建议,结果如下所示 .
Object Wrap (by Oliver Steele) – 34 % – fastest
Original solution (suggested in question) – 45%
checkNested – 50%
get_if_exist – 52%
validChain – 54%
objHasKeys – 63%
nestedPropertyExists – 69%
_.get – 72%
deeptest – 86%
sad clowns – 100% – slowest
如果您在ES6环境中编码(或使用6to5),那么您可以利用arrow function语法:
关于性能,如果设置了属性,则使用
try..catch
块不会有性能损失 . 如果未设置该属性,则会对性能产生影响 .考虑简单地使用_.has:
怎么样
ES6答案,经过彻底测试:)
→查看具有完整测试覆盖率的Codepen
我尝试了一种递归方法:
! keys.length ||
从递归开始,因此它不会运行该函数而没有剩余的密钥进行测试 . 测试:我用它来打印一堆具有未知键/值的对象的友好html视图,例如:
你也可以使用tc39可选链接提议和babel 7 - tc39-proposal-optional-chaining
代码看起来像这样:
我认为以下脚本提供了更具可读性的表示 .
声明一个函数:
然后像这样使用它:
我称之为“悲伤的小丑技术”,因为它使用的是标志o(
编辑:
这是 TypeScript 的一个版本
它在编译时提供类型检查(如果你使用像Visual Studio这样的工具,还会提供intellisense)
用法是一样的:
但这次intellisense工作!
另外,您可以设置默认值:
我没有看到任何使用Proxies的人的例子
所以我想出了自己的 . 关于它的好处是你不必插入字符串 . 你实际上可以返回一个可链式对象函数并用它做一些神奇的事情 . 您甚至可以调用函数并获取数组索引来检查深层对象
上面的代码适用于同步的东西 . 但是你如何测试像ajax调用那样异步的东西呢?你是如何测试的?如果在返回500 http错误时响应不是json怎么办?
确定你可以使用async / await来摆脱一些回调 . 但是,如果你能做得更神奇呢?看起来像这样的东西:
你可能想知道所有的承诺和
.then
链在哪里......这可能会阻塞所有你知道的...但是使用相同的代理技术和承诺你可以实际测试深层嵌套的复杂路径,而不需要写一个功能一个简单的方法是:
try/catch
捕获任何更高级别对象(如test,test.level1,test.level1.level2)未定义的情况 .一个较短的ES5版@CMS的优秀答案:
通过类似的测试:
基于this answer,我使用
ES2015
想出了这个通用函数,它可以解决问题CMS给出的答案也适用于以下对空检查的修改
以下选项从this answer开始详细阐述 . 同一棵树:
未定义时停止搜索
逐个确保每个级别
我知道这个问题很老,但我希望通过将其添加到所有对象来提供扩展 . 我知道人们倾向于使用Object原型来扩展对象功能,但我现在不允许Object.defineProperty方法使用Object.defineProperty方法 .
现在,为了测试任何对象中的任何属性,您可以简单地执行:
Here's a jsfiddle来测试它,特别是它包含一些jQuery,如果你直接修改Object.prototype因为属性变得可枚举而中断 . 这应该适用于第三方库 .
我认为这是一个小小的改进(变成一线):
这是有效的,因为&&运算符返回它评估的最终操作数(并且它是短路的) .
This works with all objects and arrays :)
例如:
这是我对Brian的答案的改进版本
我使用_has作为属性名称,因为它可能与现有的属性冲突(例如:maps)
这是fiddle
这是我的看法 - 大多数这些解决方案忽略了嵌套数组的情况,如:
我可能想查一下
obj.l2[0].k
使用下面的功能,你可以做
deeptest('l2[0].k',obj)
如果对象存在,该函数将返回true,否则返回false
现在我们也可以使用
reduce
来遍历嵌套键:我想我今天还会添加另一个 . 我为这个解决方案感到自豪的原因是它避免了许多解决方案中使用的嵌套括号,例如Object Wrap (by Oliver Steele):
(在此示例中,我使用下划线作为占位符变量,但任何变量名称都可以使用)
这是一个函数here on thecodeabode (safeRead),它将以安全的方式做到这一点......即
如果任何属性为null或未定义,则返回空字符串
我编写了自己的函数,它采用了所需的路径,并且具有好的和坏的回调函数 .
用法:
如果属性存在,我正在寻找要返回的值,所以我通过上面的CMS修改了答案 . 这就是我想出的:
我遇到了同样的问题,并希望看看我是否能想出一个自己的解决方案 . 这将接受您要检查为字符串的路径 .
这是一个包含一些日志记录和测试用例的片段:
轻微编辑为this answer以允许路径中的嵌套数组
检查用户的链接答案:)