检查未知对象中是否存在一个对象的最有效的JavaScript方法

4

在Javascript中,我经常会遇到这样的问题。假设我有一个像这样的对象:

var acquaintances = {
   types: {
      friends: {
         billy: 6,
         jascinta: 44,
         john: 91
         others: ["Matt", "Phil", "Jenny", "Anna"]
      },
      coworkers: {
         matt: 1
      }
   }
}

在我的理论程序中,我唯一确定的是acquaintances是一个对象;我不知道是否已经设置了acquaintances.types或者其中是否设置了friends

我该如何高效地检查acquaintances.types.friends.others是否存在?

通常我会这样做:

if(acquaintances.types){
  if(aquaintances.types.friends){
    if(acquaintances.types.friends.others){
       // do stuff with the "others" array here
    } 
  }
}

除了繁琐之外,这些嵌套的if语句在实践中管理起来有点难以应对(我的对象比这个例子更复杂!)。但是如果我直接尝试类似于if(acquaintances.types.friends.others){),并且types还没有被设置,那么程序将会崩溃。
Javascript有哪些整洁、可管理的方法来解决这个问题?

CoffeeScript有一个?运算符,符合您的描述,请参见此处。不知道在普通JS中是否有简单的技巧。 - Jokester
2
顺便说一句,就执行时间而言,它并不更高效 - Jokester
4个回答

5
一个替代的方法是:
((acquaintances.types || {}).friends || {}).others

这种方法比其他解决方案更短,但可能并不会让你兴奋。

你还可以构建一个小助手,使相同的想法稍微更易接受一些:

function maybe(o) { return o || {}; }

现在你可以做
maybe(maybe(acquaintances.types).friends).others

如果你不介意将属性名称写成字符串,你可以编写一个小助手:
function maybe(obj) {
  return Object.defineProperty(
    obj || {}, 
    'get', 
    { value: function(prop) { return maybe(obj[prop]); }
  );
}

现在你可以写
maybe(acquaintances.types').get('friends').others

在ES6中,您可以使用带有默认值的解构赋值来实现这一点,尽管有些笨拙。
var { types: { friends: { others } = {} } = {} } = acquaintances;

如果你想在表达式上下文中使用它,而不是赋值给一个变量,在理论上你可以使用参数解构:

(({ types: { friends: { others } = {} } = {} }) => others)(acquaintances)

毕竟,标准方法仍然是最佳选择。
acquaintances.types && 
  acquaintances.types.friends && 
  acquaintances.types.friends.others

这就是为什么 ES6 设计组有一个活跃的 discussion,讨论类似 CoffeeScript 的存在运算符,但进展似乎不是很快。

3

在JavaScript中,这并不好。

你可以将它们添加到一个大的条件语句中...

if (obj.prop && obj.prop.someOtherProp) { }

...或者编写一个助手函数,其中您需要传递一个对象和一个字符串...

var isPropSet = function(object, propPath) {
    return !! propPath.split('.')
           .reduce(function(object, prop) { return object[prop] || {}; }, object);
};

isPropSet(obj, 'prop.someOtherProp);

...或者你可以使用 CoffeeScript 和它的 ? 运算符...

obj.prop?.someOtherProp

您也可以使用 try/catch 来包装查找,但我不建议这样做。


我认为你需要写成 return object[prop] || {};;否则像 isPropSet(obj, 'prop.foo.bar') 这样的调用会产生运行时错误。 - user663031
@torazaburo 是的,你说得对,在测试属性时不应该出现错误。 - alex

3

and 运算符是顺序执行的,因此您可以在不嵌套 if 语句的情况下执行此操作。

if(acquaintances.types && aquaintances.types.friends && acquaintances.types.friends.others){
    //acquaintances.types.friends.others exists!
}

2

不要这样做:

if(acquaintances.types){
  if(aquaintances.types.friends){
    if(acquaintances.types.friends.others){
       // do stuff with the "others" array here
    } 
  }
}

试试这个:

   if(acquaintances &&
      acquaintances.types &&
      acquaintances.types.friends &&
      acquaintances.types.friends.others) {
    }

或者

acquaintances &&
acquaintances.types &&
acquaintances.types.friends &&
acquaintances.types.friends.others ?
doSomething() : doSomethingElse()

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