如何遍历JavaScript对象并检查null值?

3

假设我有一个JavaScript对象:

var obj = {};
obj.computers = {};
obj.computers.favorite = "Commodore 64";
obj.computers.popular = "Apple";

现在,我可以轻松地检查 null 值,如下所示:
if(obj != 'undefined' && obj != null) {
    if(obj.computers != 'undefined' && obj.computers != null)) {
        .....

如您所见,如果我需要查看 obj.computers.favorite 是否已设置,我必须在那里嵌套一些条件逻辑。我们的一些对象会有3、4、5层。

这就是我想要做的:

var fav = obj.computers.favorite || 'Unknown';

但我意识到我需要将其包装在某个方法中。类似于:
var fav = getValueOrDefault(obj.computers.favorite, 'Unknown');

欢迎提出建议。

谢谢。

编辑

我实际使用的并不是检查'undefined'的方法。这只是在问问题时从我的脑海中冒出来的。哈哈

但我想知道,如果出现异常,我能否直接用try / catch包装并抛出默认值?

function(obj, default) {
    try {
        if(obj != null) {
            return obj;
        } else {
            return default;
        }
    } catch(ex) {
        return default;
    }
}

此外,感谢Shusi指出了冗余的变量。

obj != 'undefined' && obj != null 是不正确的,因为要获取字符串值 'undefined',需要使用 typeof。这是一个常见的错误。但无论如何,这样做过于冗长。只需使用 obj != null,它将同时测试 undefined - I Hate Lazy
如果obj.computers未定义,getValueOrDefault(obj.computers.favorite, 'Unknown')将抛出异常。您需要将其包装在字符串中并进行递增对象解析。 - saml
@saml 没错。这也是我想要避免的。我们的JS对象有时会非常深。我猜我可以尝试使用try/catch并在异常情况下返回默认值? - cbmeeks
可选链式调用是你想要的。 - zoran404
7个回答

6

你可以真正地编写:

(obj && obj.computers && obj.computers.favorite) || 'Unknown'

+1,但请看一下我的答案,其中包含了一个通用解决方案,它不会用太多的“and”来弄乱代码,并且如果 OP 多次使用此模式,则更加有用。 - Raffaele

3
你可以使用一个辅助函数来实现。如果我正确理解你的问题,你的对象可能具有任意深度的对象,并且你希望访问这些任意嵌套属性而不会使你的代码混乱。我建立了一个 Nested 函数,它允许你在属性被设置时获取任意属性,或者在属性未被设置时获取默认值。
var Nested = function() {};
// prop is a dot-separated path like "foo.bar.baz"
Nested.prototype.get = function(prop, _default) {
    var current = this;
    $.each(prop.split("."), function(i, e) {
        current = current[e] || undefined;
        if (current == undefined)
            return false;
    });
    return current || _default;
}

你可以像这样编写代码。
var fav = obj.get("computers.favourite", "Linux");
// this emulates
var fav = obj.computers.favourite || "Linux"; // throws error

正如您所看到的,它并不需要更多的打字。当然,它不像常规Javascript那样...这里是代码示例


1
错误,您需要将变量声明更改为 var current = this; 并在代码中使用 current = current[e] || undefined;。然后 fiddle 将正常工作。 - user757095
你应该提到你的答案需要使用 jQuery。 - DrCord

3

我写这篇文章来帮助你解决一个问题:“我需要查看obj.computers.favorite是否被设置”。

Object.prototype.isset = function (/* string */ full_path)
{
    var props = full_path.split('.');
    var self = this; /* note that self is usually the window object */

    for (var ii = 0; ii < props.length; ++ii)
    {
        var prop = props[ii];
        var hasMoreComing = ii < props.length - 1 ? true : false;

        if (self[prop] !== null && typeof self[prop] === 'object' && hasMoreComing)
        {
            self = self[prop];
            continue;   // Move up one level.
        }
        else if (hasMoreComing)
            return false;    // ..because user queries a subproperty of a value type

        return self.hasOwnProperty(prop);
    }
};

测试代码:

var test = {};

test.kuk = {};
console.log( test.isset('kuk') );  // Prints true.

test.kuk.fitta = {};
console.log( test.isset('kuk.fitta') ); // Prints true.

test.kuk.fitta = null;
console.log( test.isset('kuk.fitta') ); // Prints true.

test.kuk.fitta = undefined;
console.log( test.isset('kuk.fitta') );  // Prints true

delete test.kuk.fitta;
console.log( test.isset('kuk.fitta') );  // Prints false

test.kuk.fitta = 123;
console.log( test.isset('kuk.fitta.doesnt.exist') );  // Prints false

这与 PHP 的 isset 不同,因为它对于 null 和 undefined 返回 true。 - DrCord

1

可选链操作符是一种更为新的处理方式:

let favorite = obj?.computers?.favorite;

将此与nullish coalescing operator结合,您可以精确地执行最初请求的操作:
let favorite = obj?.computers?.favorite ?? 'Unknown';

请注意,目前这两个运算符都还没有得到普遍的支持。

1
以下函数将以字符串作为参数并返回对象(如果存在)。
 function getValueOrDefault(str , obj, deflt){
    var a = str.split("."); o = obj;
    for(var i =0; i < a.length; i++){
         o = obj[a[i]];
         if(!o){
           return deflt;
         }
    }
      return o;
}

var obj = {};
obj.computers = {};
obj.computers.favorite = "Commodore 64";
obj.computers.popular = "Apple";
getValueOrDefault('computers.favorite', obj, 'Unknown');

注意:在给对象分配属性时,不能使用var,例如var obj.computers.favorite是语法错误。

我认为你可以交换 objdeflt 参数,并更改 o = obj || window。 这样,你就可以写成 getValueOrDefault('obj.computers.favorite', 'unknown') - user757095
是的,你说得对。但是这个解决方案更加针对上面的问题。 - Anoop

1

不幸的是,没有一种超级简单的方法可以解决这个问题,但您不需要检查null和undefined。因为null和undefined都是falsey,所以您只需执行:

if (obj && obj.computers) {
  var fav = obj.computers.favorite || 'unknown';
}

它并没有解决你的投诉,但比你想象的要少痛苦。


0

你也可以使用 JavaScript ES5reduce 函数来实现:

function get(root, member) {
    return member.split('.').reduce((acc, value) => {
        return (acc && typeof acc[value] !== 'undefined') ? acc[value] : undefined
    }, root);
}

它将成员字符串转换为数组,然后累加器随着成员的减少而在对象内部逐步遍历。

即使是数组,您也可以像这样使用它:

let obj = {
    computers : {
        favorite : "Commodore 64",
        popular : "Apple",
        list: [
            {
                sn : "TDGE52343FD76",
                price: "9867.99",
                options: {
                    fanless: true
                }
            }
        ]
    }
}

get(obj, 'computers.popular');
// => "Apple"
get(obj, 'computers.list.0.sn');
// => "TDGE52343FD76"
get(obj, 'computers.list.0.options.fanless');
// => true
get(obj, 'computers.list.0.options.runsWithoutEletricity');
// => undefined
get(obj, 'computers.list.0.options.runsWithoutEletricity') || "too bad..." ;
// => "too bad..."

这里有一个 CodePen 可以安全遍历 JavaScript 对象


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接