Shorthand function for checking whether a property exists [duplicate]
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).
精彩评论