【问题标题】:Shorthand function for checking whether a property exists [duplicate]检查属性是否存在的速记函数[重复]
【发布时间】:2011-09-28 03:08:38
【问题描述】:

你们能帮我做一个简写函数来确定对象属性是否存在吗?在 99% 的情况下,我想用它来检查返回的 json 对象是否包含指定的属性。请注意,不保证必须定义任何父属性甚至 json 对象本身。

我是这样想的:

function propertyExists(<property>) {
    // property is something like data.property.property
    return typeof(data) !== "undefined" && typeof(data.property) !== "undefined" && typeof(data.property.property) !== "undefined";
}

我不知道如何以动态方式编写它来检查所有父属性。此外,in-parameter 应该只是对“data.property.property”的引用,而不是字符串,所以我也不知道如何在其中找到父属性。

【问题讨论】:

  • in 测试可能比 typeof 更好。最近有人问这个问题,可能很快就会有人发布链接。

标签: javascript jquery function properties exists


【解决方案1】:

这是我在一个项目中发现的一个函数,它告诉你是否定义了一个属性(包括它的所有父属性,如果有的话):

function isDefined(target, path) {
    if (typeof target != 'object' || target == null) {
        return false;
    }

    var parts = path.split('.');

    while(parts.length) {
        var branch = parts.shift();
        if (!(branch in target)) {
            return false;
        }

        target = target[branch];
    }

    return true;
}

应该是这样使用的:

var data = { foo: { bar: 42 } };
isDefined(data, "foo"); // true
isDefined(data, "foo.bar"); // true
isDefined(data, "notfoo"); // false
isDefined(data, "foo.baz"); // false

您可以轻松调整它以返回值本身(或 null)而不是 true/false

更新:在阅读了有关问题的 cmets 后,我在 Javascript 上搜索了 in 运算符并用它替换了 typeof 测试。现在代码是按照“它的本意”编写的。

【讨论】:

  • 我喜欢这个 - 我怎么能假设 isDefined("foo.bar") 总是应该在目标“foo”上作为一个对象进行检查?如果 foo = {} 应该适用于 isDefined("foo"),如果 foo = {a:{b:{}}} 应该适用于 isDefined("foo.a.b")
  • @Yonder:不确定你的意思。可能通过将=== 'undefined' 更改为=== 'object'
  • 我的意思是将签名更改为函数 isDefined(path) -> 从路径中派生目标(“foo.bar”中的“foo”)。
  • 我也使用类似的东西,效果很好。 @Yonder,我想你会这样传递它:isDefined(foo, "bar") 其中foo 是你想要开始检查的target 对象。看看 Jon 给出的例子——他传入data 作为目标,然后检查foo.bar。如此有效,您拥有“data.foo.bar”。
  • @Yonder:在一般情况下,这是不可能的。 function isDefined 应该如何拉例如foo 来自其 调用者的 范围?您能做的最好的事情就是丢失参数并执行var target = window;,但随后您也无法定位没有全局范围的对象。
【解决方案2】:

目前我找不到其他帖子,很确定以下内容是正确的:

function checkAccess(obj, path) {
  var path = path.split('.');
  var prop;

  for (var i=0, iLen=path.length; i<iLen; i++) {
    if (obj !== null && typeof obj == 'object') {
      prop = path[i];

      if (prop in obj) {
        obj = obj[prop];
      }
    } else {
      return false
    }
  }
  return true;
}

var o = {foo:{bar:null}};

alert(checkAccess(o, 'foo.bar')); // true
alert(checkAccess(o, 'foo.bar.baz')); // false

请注意,这对于 JSON 应该没问题,但如果涉及主机对象,则所有赌注都将关闭,因为 typeof 不能保证返回 object (或任何东西)那个案子。如果您需要测试主机对象,try..catch 可能是最可靠的解决方案,除非您确信正在测试的对象将返回预期结果。

try {
  alert( o.foo.bar.baz);
} catch(e) {
  alert( 'oops');
}

如果你想使用单个参数,那么我假设基础对象是一个全局属性:

var checkAccess = (function(global) {
  return function (expr) {
    var path = expr.split('.');
    var obj, prop;

    if (path.length) {
      obj = global[path.shift()];

      for (var i=0, iLen=path.length; i<iLen; i++) {
        if (obj !== null && typeof obj == 'object') {
          prop = path[i];

          if (prop in obj) {
            obj = obj[prop];
          }
        } else {
          return false
        }
      }
      return true;
    }
    return false;
  }
}(this));

编辑

请注意,以上只是意味着尝试访问路径不会返回错误,并不意味着它会返回一个值(它可能是未定义的、null 或其他)。

【讨论】:

    【解决方案3】:

    JSON 属性允许包含点,如 {"a.b": 42} 中的点,这使得点字符串不适合对对象进行“深度引用”。

    isDefined({"a.b": 42}, 'a.b') // false
    isDefined({"a": 42}, 'a.b') // TypeError
    

    因此,数组可能是引用或索引的更好选择

    function hasProperty(value, index) {
        if (index instanceof Array) {
            return index.length === 0 ||
                (hasProperty(value, index[0])
                    && hasProperty(value[index[0]], index.slice(1)));
        }
        return value.hasOwnProperty(index);
    }
    

    它是这样使用的:

    hasProperty(42, []); // true
    hasProperty(42, ['a']); // false
    hasProperty(42, ['a']); // false
    hasProperty({a: 42}, 'a'); // true
    hasProperty({a: 42}, ['a']); // true
    hasProperty({a: 42}, ['a', 'b']); // false
    hasProperty({a: {b: 42}}, ['a', 'b']); // true
    hasProperty({"a.b": 42}, ['a.b']); // true
    hasProperty([1,2,3], 2); // true
    hasProperty([1,2,3], 3); // false
    hasProperty({a: {b: [1,2,3]}}, ['a', 'b', 2]); // true
    

    请注意,hasProperty 会忽略原型中的属性,因为使用了原型函数 hasOwnProperty

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-28
      • 2020-05-08
      • 2016-09-22
      • 2018-02-28
      相关资源
      最近更新 更多