检查 JavaScript 中深层嵌套对象属性是否存在的最简单方法是什么?

IT技术 javascript properties
2021-03-19 00:38:52

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

我目前使用的代码是

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

这有效,但看起来很笨拙。

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

6个回答

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

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
}
当您通常期望它存在时不存在的中间属性很可能是“改变程序执行正常流程的特殊条件”,并且似乎是异常的完美用途。您似乎认为异常应该只用于非同寻常的事情,但它们只是另一种错误返回/传播机制,if在许多情况下可以比多个语句更有效地使用,尤其是当您处理外部输入时不一定要控制,并且测试每一个操作可能非常昂贵。
2021-04-24 00:38:52
@Raynos - 为什么会滥用 try/catch?对我来说,比检查所有中间级别的多个嵌套 if 语句更有意义。空捕获只是意味着如果中间级别不存在(合理的设计选择),您故意什么都不做。这是完美的代码。您实际上是否因为更喜欢不同的方法而拒绝投票?像这样使用 try/catch 绝对没有错。
2021-04-29 00:38:52
在对应该遵守特定格式但可能有错误的外部 HTML(不受我控制的 HTML)进行操作时,我一直都使用异常。当开始时有一堆内务处理(解析结构,获取数据等),然后在最后应用最终结果时,它特别有用。我用 try/catch 包围整个块,如果任何结构不符合预期,它就会抛出一个错误,我非常有效地在一个地方捕获所有错误,而不是使用几十个if语句。也使代码更具可读性。
2021-05-10 00:38:52
“异常的发生,改变程序执行正常流程的特殊情况。” 我发现声称不存在的属性是“改变程序执行正常流程的特殊条件”是一种巨大的延伸。我认为您在工作中使用了错误的工具。
2021-05-16 00:38:52
不要滥用 try catch 那样。亲爱的上帝,我的眼睛。甚至是一个空的 catch 块。如果我见过的话,这是一种代码气味。
2021-05-21 00:38:52
var _ = {};

var x = ((YAHOO.Foo || _).Bar || _).xyz;
为本周最不清楚的路线竖起大拇指。
2021-04-29 00:38:52

考虑这个效用函数:

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/

这是一个非常好的解决方案。但是如果引用对象未定义,代码就会中断。我认为检查引用对象是否已定义将解决问题。你的解决方案更新了一个
2021-05-02 00:38:52
哦 lodash 实际上拥有它。_.get(),太棒了!甚至有一个默认参数。
2021-05-03 00:38:52
我希望在下划线或 lodash 中有这样的东西
2021-05-10 00:38:52
@codebox 我对我的代码不满意,所以我重写了。你怎么认为?
2021-05-14 00:38:52
我认为您需要在 while 循环测试中对 undefined 进行显式检查,而不仅仅是真实性测试。目前定义({a:''},'a.b')===真。不过方法不错,我喜欢!
2021-05-16 00:38:52

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

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

或者,您可以执行一些 string-kong-fu-magic TM

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 方法?
2021-04-23 00:38:52
@missingno:它检查用户提供的“obj”(这是可选的;window如果没有提供,它默认为),实际上是一个对象(如果用户传递错误的参数,它会停止函数中断,基本上!)
2021-04-28 00:38:52
@jfriend00:字符串方法允许你找到事情崩溃的点(如果你碰巧也想要)。在某些情况下,例如自定义module系统,通过字符串传递对象描述也是有意义的。
2021-05-07 00:38:52
我只是没有看到typeof obj !== "object"测试的意义。为什么要限制?
2021-05-21 00:38:52
@jfriend00:try/catch如果您有很多地方要检查对象路径是否存在,则需要输入一些内容。
2021-05-21 00:38:52

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

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