如果我有对象的引用:
var test = {};
可能(但不是立即)具有嵌套对象,例如:
{level1: {level2: {level3: "level3"}}};
检查深度嵌套对象中是否存在属性的最佳方法是什么?
警报(测试级别1);生成未定义,但警告(test.level1.level2.level3);失败。
我目前正在做这样的事情:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
但我想知道是否有更好的方法。
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
今天刚刚编写了这个函数,它对嵌套对象中的属性进行了深入搜索,如果找到了,则返回该属性的值。
/**
* Performs a deep search looking for the existence of a property in a
* nested object. Supports namespaced search: Passing a string with
* a parent sub-object where the property key may exist speeds up
* search, for instance: Say you have a nested object and you know for
* certain the property/literal you're looking for is within a certain
* sub-object, you can speed the search up by passing "level2Obj.targetProp"
* @param {object} obj Object to search
* @param {object} key Key to search for
* @return {*} Returns the value (if any) located at the key
*/
var getPropByKey = function( obj, key ) {
var ret = false, ns = key.split("."),
args = arguments,
alen = args.length;
// Search starting with provided namespace
if ( ns.length > 1 ) {
obj = (libName).getPropByKey( obj, ns[0] );
key = ns[1];
}
// Look for a property in the object
if ( key in obj ) {
return obj[key];
} else {
for ( var o in obj ) {
if ( (libName).isPlainObject( obj[o] ) ) {
ret = (libName).getPropByKey( obj[o], key );
if ( ret === 0 || ret === undefined || ret ) {
return ret;
}
}
}
}
return false;
}
我的解决方案,我使用了很长时间(使用字符串不幸,找不到更好的)
function get_if_exist(str){
try{return eval(str)}
catch(e){return undefined}
}
// way to use
if(get_if_exist('test.level1.level2.level3')) {
alert(test.level1.level2.level3);
}
// or simply
alert(get_if_exist('test.level1.level2.level3'));
edit:只有当对象“test”具有全局范围/范围时,这才有效。否则您必须执行以下操作:
// i think it's the most beautiful code I have ever write :p
function get_if_exist(obj){
return arguments.length==1 || (obj[arguments[1]] && get_if_exist.apply(this,[obj[arguments[1]]].concat([].slice.call(arguments,2))));
}
alert(get_if_exist(test,'level1','level2','level3'));
编辑最终版本以允许2种调用方法:
function get_if_exist(obj){
var a=arguments, b=a.callee; // replace a.callee by the function name you choose because callee is depreceate, in this case : get_if_exist
// version 1 calling the version 2
if(a[1] && ~a[1].indexOf('.'))
return b.apply(this,[obj].concat(a[1].split('.')));
// version 2
return a.length==1 ? a[0] : (obj[a[1]] && b.apply(this,[obj[a[1]]].concat([].slice.call(a,2))));
}
// method 1
get_if_exist(test,'level1.level2.level3');
// method 2
get_if_exist(test,'level1','level2','level3');
这有一个小模式,但在某些时候可能会让人不知所措。我建议您一次使用两个或三个嵌套。
if (!(foo.bar || {}).weep) return;
// Return if there isn't a 'foo.bar' or 'foo.bar.weep'.
正如我可能忘记提到的,你也可以进一步扩展。下面的示例显示了对嵌套foo.bar.weep.woop的检查,如果没有可用的,则返回。
if (!((foo.bar || {}).weep || {}).woop) return;
// So, return if there isn't a 'foo.bar', 'foo.bar.weep', or 'foo.bar.weep.woop'.
// More than this would be overwhelming.