什么';在处理多个级别的对象时,确保JavaScript对象已设置且未定义的最佳实践是什么?

什么';在处理多个级别的对象时,确保JavaScript对象已设置且未定义的最佳实践是什么?,javascript,jquery,Javascript,Jquery,我是一名js开发人员,工作环境是我们进行API调用并返回一些数据。返回的数据的结构高度不一致,因此我们不能对返回的数据做任何假设 想象一下以下场景: $.ajax({ success: function(data){ // Now I want to access a property 4 levels in var length = data.results.users.length; doSomeStuffWithLength(leng

我是一名js开发人员,工作环境是我们进行API调用并返回一些数据。返回的数据的结构高度不一致,因此我们不能对返回的数据做任何假设

想象一下以下场景:

$.ajax({
    success: function(data){
        // Now I want to access a property 4 levels in
        var length = data.results.users.length;
        doSomeStuffWithLength(length);
    }
})
确保未定义
数据.results.users.length
的正确方法是什么?由于API的不一致性,返回对象的每个级别都可能被破坏/未定义。我真的必须做以下事情吗:

if (data && data.results && data.results.users && data.results.users.length){
    var length = data.results.users.length;
    doSomeStuffWithLength(length);
}
function getPropByPath(obj, path){
  var parts = path.split('.'),
      root = obj;

  for(var i=0; i<parts.length; i++) {
    if(root[parts[i]] !== 'undefined') {
      root = root[parts[i]]
    } else {
      return false;
    }
  }
  return root;
}

难道没有更优雅的解决方案吗?

如果在所有级别上都有未定义的内容,您应该检查所有级别,例如:

var length = data && 
             data.results && 
             data.results.users && 
             data.results.users.length || 0;
您还可以使用一些辅助函数。这里有一个:

function getPropValue ( path, defaultIfNotExisting ) {
  defaultIfNotExisting = defaultIfNotExisting || 0;
  path = path.split('.'), test = this;
  while (path.length) {
    test = test[path.shift()];
    if (!test) {
      return defaultIfNotExisting;
    }
  }
  return test;
}
// usage in your case:
if ( getPropValue.call(data, 'results.users', []).length) { /* do stuff */}

如果所有级别都有未定义的内容,则应检查所有级别,例如:

var length = data && 
             data.results && 
             data.results.users && 
             data.results.users.length || 0;
您还可以使用一些辅助函数。这里有一个:

function getPropValue ( path, defaultIfNotExisting ) {
  defaultIfNotExisting = defaultIfNotExisting || 0;
  path = path.split('.'), test = this;
  while (path.length) {
    test = test[path.shift()];
    if (!test) {
      return defaultIfNotExisting;
    }
  }
  return test;
}
// usage in your case:
if ( getPropValue.call(data, 'results.users', []).length) { /* do stuff */}

您可以像这样创建助手函数。 预期对象的结构如下:

var someObj = {
  some: {
    other: {
      third: 'bingo',
      qwe: 'test'
    }
  }
};
如果有这样的东西就太好了

getPropByPath(someObj, 'some.other.qwe');
因此,
getPropByPath
的实现可能如下所示:

if (data && data.results && data.results.users && data.results.users.length){
    var length = data.results.users.length;
    doSomeStuffWithLength(length);
}
function getPropByPath(obj, path){
  var parts = path.split('.'),
      root = obj;

  for(var i=0; i<parts.length; i++) {
    if(root[parts[i]] !== 'undefined') {
      root = root[parts[i]]
    } else {
      return false;
    }
  }
  return root;
}
函数getPropByPath(obj,路径){ var parts=path.split('.'), 根=obj;
对于(var i=0;i,您可以像这样创建helper函数。 预期对象的结构如下:

var someObj = {
  some: {
    other: {
      third: 'bingo',
      qwe: 'test'
    }
  }
};
如果有这样的东西就太好了

getPropByPath(someObj, 'some.other.qwe');
因此,
getPropByPath
的实现可能如下所示:

if (data && data.results && data.results.users && data.results.users.length){
    var length = data.results.users.length;
    doSomeStuffWithLength(length);
}
function getPropByPath(obj, path){
  var parts = path.split('.'),
      root = obj;

  for(var i=0; i<parts.length; i++) {
    if(root[parts[i]] !== 'undefined') {
      root = root[parts[i]]
    } else {
      return false;
    }
  }
  return root;
}
函数getPropByPath(obj,路径){ var parts=path.split('.'), 根=obj;
对于(var i=0;i向帮助程序提供空数组作为参数的原因是什么?再加上检查
length
-if函数返回数如何?@evgeny:这是因为检查涉及检查返回值的
length
属性。如果
length
为0,则表达式的计算结果为
fals(e/y)
因此,如果getPropValue retursn int 4,您将尝试检查int length并接收未定义的
作为结果,尽管函数返回值作为属性doessent existYep进行处理,在本例中为true。请阅读答案中的注释:
//在您的情况下使用*
。创建/使用帮助器方法不会改变改变程序员需要考虑如何使用它们的事实。为什么要将空数组作为参数提供给帮助程序?再加上检查
length
-if函数返回数如何?Evgeniy:这是因为检查涉及检查返回值的
length
属性。if
length
是0,表达式的计算结果为
fals(e/y)
因此,如果getPropValue retursn int 4,您将尝试检查int length并接收未定义的
作为结果,尽管函数返回值作为属性doessent existYep进行处理,在本例中为true。请阅读答案中的注释:
//在您的情况下使用*
。创建/使用帮助器方法不会改变改变程序员需要考虑如何使用它们的事实。对于您的解决方案-在OPs情况下,他/她需要做:
if(getPropByPath(数据,'results.users')&&getPropByPath(数据,'results.users').length)
?看起来有点多余。@KooiInc-hm,不确定你的观点是否正确。我的助手只返回属性值is exists或false。在中描述的情况下,
var-value=getPropByPath(数据,'results.users')| |[]//或者您需要作为默认值的任何其他数据类型,lng=value.length
@Evgeniy在for循环中不应该是i=1吗?否则您将从主对象开始。@web潜伏,不,我们应该从0开始。如果我们从1开始,将在主对象中检查第一个属性,它将是
其他
,但它不存在。想法是获取
>root
object,检查第一个属性是否存在,然后深入并将
root
移动到此嵌套属性或返回False以获取解决方案-在OPs情况下,他/她需要执行:
if(getPropByPath(data,'results.users')&&getPropByPath(data,'results.users')。length)
?看起来有点多余。@KooiInc-hm,不确定你的观点是否正确。我的助手只返回属性值is exists或false。在中描述的情况下,
var-value=getPropByPath(数据,'results.users')| |[]//或者您需要作为默认值的任何其他数据类型,lng=value.length
@Evgeniy在for循环中不应该是i=1吗?否则您将从主对象开始。@web潜伏,不,我们应该从0开始。如果我们从1开始,将在主对象中检查第一个属性,它将是
其他
,但它不存在。想法是获取
>root
对象,检查第一个属性是否存在,然后深入并将
root
移动到此嵌套属性或返回false