开发者

Shorthand function for checking whether a property exists [duplicate]

This question already has answers here: Test for existence of nested JavaScript object key (64 answers) Closed 7 years ago.

Can you guys help me make a shorthand function determining whether an objec开发者_运维知识库t property exists? In 99% of the cases I want to use it to check whether the returned json object contains the specified property or not. Note that there is no guarantee that any of the parent properties or even the json object itself must be defined.

I was thinking of something in this manner:

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

I don't know how to write it in a dynamic manner to check all the parent properties. Also the in-parameter should be just a reference to the "data.property.property" and not a string, so I don't know how to find the parent properties within that either.


Here's a function I have lying around from a project that tells you if a property is defined (including all of its parent properties, if any):

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;
}

It's supposed to be used like this:

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

You can easily tweak this to return the value itself (or null) instead of true/false.

Update: After reading the comments on the question, I googled the Javascript in operator and replaced the typeof test with that. Now the code is written "how it was meant to be".


JSON properties are allowed to contain dots as in {"a.b": 42} which makes a dot-string unsuitable for a "deep reference" into an object.

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

So an array may a better choice for a reference or index

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);
}

It is used like this:

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

Note that hasProperty ignores properties from the prototype due to the use of the prototype function hasOwnProperty.


I can't find other posts at the moment, pretty sure the following is on the right track:

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

Note that this should be fine for JSON, but if host objects are involved, all bets are off as typeof is not guaranteed to return object (or anything) in that case. If you need to test host objects, likely try..catch would be the most robust solution unless you are confident that the objects being tested will return expected results.

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

If you want to use a single parameter, then I'll assume that the base object is a global property:

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));

Edit

Note that the above just means that attempting to access the path will not return an error, it doesn't mean that it will return a value (it may be undefined, null, or something else).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜