检查 JavaScript 中是不是存在深度嵌套对象属性的最简单方法是啥? [复制]

Posted

技术标签:

【中文标题】检查 JavaScript 中是不是存在深度嵌套对象属性的最简单方法是啥? [复制]【英文标题】:What's the simplest approach to check existence of deeply-nested object property in JavaScript? [duplicate]检查 JavaScript 中是否存在深度嵌套对象属性的最简单方法是什么? [复制] 【发布时间】:2011-10-19 03:02:22 【问题描述】:

我必须检查深度嵌套的对象属性,例如 YAHOO.Foo.Bar.xyz

我目前使用的代码是

if (YAHOO && YAHOO.Foo && YAHOO.Foo.Bar && YAHOO.Foo.Bar.xyz) 
    // operate on YAHOO.Foo.Bar.xyz

这可行,但看起来很笨拙。

有没有更好的方法来检查这种深度嵌套的属性?

【问题讨论】:

你不能只做if (YAHOO.Foo.Bar.xyz)吗? enterprise-js.com/34 @Michael,你不能只做if (YAHOO.Foo.Bar.xyz),因为如果 Foo 或 Bar 不存在,那么 if (YAHOO.Foo.Bar.xyz) 会因为取消引用未定义的中间值而引发异常。 这可能是最好的检查方法;使用try...catch 会影响性能——当抛出异常时,代码会变慢。 jsPerf test. @Digital Plane - 但是,如果正常情况是它存在,那么 try/catch 比多重 if 测试(在 Chrome 中)快 19 倍。 【参考方案1】:

如果您希望YAHOO.Foo.Bar 是一个有效的对象,但又想让您的代码防弹以防万一它不是,那么在它周围放置一个 try catch 并让一个错误处理程序捕获任何可能是最干净的缺失的部分。然后,您可以只使用一个 if 条件而不是四个来检测终端属性是否存在,如果中间对象不存在,则使用一个 catch 处理程序来捕获事物:

try 
    if (YAHOO.Foo.Bar.xyz) 
        // operate on YAHOO.Foo.Bar.xyz
 catch(e) 
    // handle error here

或者,根据您的代码的工作方式,它甚至可能只是这样:

try 
    // operate on YAHOO.Foo.Bar.xyz
 catch(e) 
    // do whatever you want to do when YAHOO.Foo.Bar.xyz doesn't exist

在处理应该是特定格式的外部输入时,我特别使用这些,但无效输入是我想要捕获和处理自己的可能性,而不是仅仅让异常向上传播。

一般来说,一些 javascript 开发人员未充分使用 try/catch。我发现有时我可以用围绕较大功能块的单个 try/catch 替换 5-10 if 语句检查输入,同时使代码更简单且更具可读性。显然,何时合适取决于特定的代码,但绝对值得考虑。

仅供参考,如果通常的操作是不使用 try/catch 抛出异常,它也可以比一堆 if 语句快得多。


如果您不想使用异常处理程序,您可以创建一个函数来为您测试任意路径:

function checkPath(base, path) 
    var current = base;
    var components = path.split(".");
    for (var i = 0; i < components.length; i++) 
        if ((typeof current !== "object") || (!current.hasOwnProperty(components[i]))) 
            return false;
        
        current = current[components[i]];
    
    return true;

示例用法:

var a = b: c: d: 5;
if (checkPath(a, "b.c.d")) 
    // a.b.c.d exists and can be safely accessed

【讨论】:

不要这样滥用try catch。亲爱的上帝,我的眼睛。甚至是一个空的 catch 块。如果我见过的话,这是一种代码味道。 @Raynos - 为什么这会滥用 try/catch?对我来说,检查所有中间级别比使用多个嵌套 if 语句更有意义。一个空的捕获只是意味着如果中间级别不存在,你故意不做任何事情(一个合理的设计选择)。这是非常好的代码。您是否真的因为喜欢不同的方法而投反对票?像这样使用 try/catch 绝对没有错。 “异常的发生,改变程序正常执行流程的特殊情况。”我发现声称不存在的属性是“改变程序执行正常流程的特殊条件”是一个巨大的延伸。我认为您使用了错误的工具来完成这项工作。 当您通常期望它存在时不存在的中间属性很可能是“改变程序正常执行流程的特殊条件”,并且似乎是异常的完美用途。您似乎认为异常应该只用于特殊的事情,但它们只是另一种错误返回/传播机制,在许多情况下可以比多个if 语句更有效地使用,特别是当您处理外国您不一定要控制的输入,并且测试每个操作可能会非常昂贵。 在处理应该遵守特定格式但可能有错误的外来 html(不受我控制的 HTML)时,我一直使用异常。当一开始有一堆家务(解析结构,获取数据等),然后在最后应用最终结果时,它特别有用。我用 try/catch 包围整个块,如果任何结构不符合预期,它会引发错误,并且我非常有效地在一个地方捕获所有错误,而不是使用数十个 if 语句。也使代码更具可读性。【参考方案2】:

coffeescript(编译成javascript)很好地解决了这个问题:

if YAHOO.Foo?.Bar?.xyz
  // operate on YAHOO.Foo.Bar.xyz

【讨论】:

【参考方案3】:

考虑这个效用函数:

function defined(ref, strNames) 
    var name;
    var arrNames = strNames.split('.');

    while (name = arrNames.shift())         
        if (!ref.hasOwnProperty(name)) return false;
        ref = ref[name];
     

    return true;

用法:

if (defined(YAHOO, 'Foo.Bar.xyz')) 
    // operate on YAHOO.Foo.Bar.xyz

现场演示: http://jsfiddle.net/DWefK/5/

【讨论】:

我认为您需要在 while 循环测试中明确检查 undefined,而不仅仅是真实性测试。此刻定义(a:'','a.b')=== true。不错的方法,我喜欢它! @codebox 我对我的代码不满意,所以我重写了。你怎么看? 我希望在下划线或 lodash 中有这样的内容 哦 lodash 确实有。 _.get(),太棒了!甚至还有一个默认参数。 这是一个非常好的解决方案。但是如果引用对象未定义,代码就会中断。我认为检查是否定义了引用对象将解决问题。 Your solution, Updated one【参考方案4】:
var _ = ;

var x = ((YAHOO.Foo || _).Bar || _).xyz;

【讨论】:

为本周最不清楚的一行点赞。【参考方案5】:

我实际上投票结束了作为javascript convert dotnotation string into objects重复的问题。

但是,我想这是一个不同的主题,但如果您不想一直try-catch,那么那里的答案可能仍然有用。

【讨论】:

【参考方案6】:

如果您需要检查路径的正确性,而不是“YAHOO.Foo.Bar”对象上是否存在“xyz”成员,将调用包装在 try catch 中可能是最简单的:

var xyz;
try 
    xyz = YAHOO.Foo.Bar.xyz;
 catch (e) 
    // fail;
;

或者,你可以做一些 string-kong-fu-magicTM

function checkExists (key, obj) 
    obj = obj || window;
    key = key.split(".");

    if (typeof obj !== "object") 
        return false;
    

    while (key.length && (obj = obj[key.shift()]) && typeof obj == "object" && obj !== null) ;

    return (!key.length && typeof obj !== "undefined");

用法如下:

if (checkExists("YAHOO.Foo.Bar.xyz")) 
    // Woo!
;

【讨论】:

你什么时候会使用 checkExists 函数中涉及的所有东西而不是 try/catch 方法? 我只是不明白typeof obj !== "object" 测试的意义。为什么要限制? @jfriend00:字符串方法可以让您找到事情发生故障的点(如果您也想这样做的话)。在某些情况下,通过字符串传递对象描述也是有意义的,例如自定义模块系统。 @missingno:它检查用户提供的“obj”(这是可选的;如果没有提供,它默认为window),实际上是一个对象(它阻止函数中断如果用户传递了错误的参数,基本上!) @jfriend00:try/catch 如果您有很多地方要检查对象路径是否存在,则有点需要输入。【参考方案7】:

使用try catch

a=
  b:
;

//a.b.c.d?true:false; Errors and stops the program.

try
  a.b.c.d;

catch(e)
  console.log(e);//Log the error
  console.log(a.b);//This will run

【讨论】:

以上是关于检查 JavaScript 中是不是存在深度嵌套对象属性的最简单方法是啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

测试嵌套 JavaScript 对象键是不是存在

MongoDB:检查嵌套键值对是不是存在

使用 Flow 对 React 中深度嵌套的 props 进行类型检查

javascript 检查嵌套对象键的存在

Spark Scala,如何检查数据框中是不是存在嵌套列

即使未定义,也检查嵌套键是不是存在[重复]