如果我有对象的引用:
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);
}
但我想知道是否有更好的方法。
我尝试了递归方法:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
这个keys.length||退出递归,这样它就不会在没有键可供测试的情况下运行函数。测验:
obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
我正在使用它打印一组具有未知键/值的对象的友好html视图,例如:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
这个功能怎么样?它不需要单独列出每个嵌套属性,而是保持“dot”语法(尽管是字符串),使其更具可读性。如果未找到属性,则返回undefined或指定的默认值,如果找到,则返回属性的值。
val(obj, element, default_value)
// Recursively checks whether a property of an object exists. Supports multiple-level nested properties separated with '.' characters.
// obj = the object to test
// element = (string or array) the name of the element to test for. To test for a multi-level nested property, separate properties with '.' characters or pass as array)
// default_value = optional default value to return if the item is not found. Returns undefined if no default_value is specified.
// Returns the element if it exists, or undefined or optional default_value if not found.
// Examples: val(obj1, 'prop1.subprop1.subsubprop2');
// val(obj2, 'p.r.o.p', 'default_value');
{
// If no element is being requested, return obj. (ends recursion - exists)
if (!element || element.length == 0) { return obj; }
// if the element isn't an object, then it can't have properties. (ends recursion - does not exist)
if (typeof obj != 'object') { return default_value; }
// Convert element to array.
if (typeof element == 'string') { element = element.split('.') }; // Split on dot (.)
// Recurse into the list of nested properties:
let first = element.shift();
return val(obj[first], element, default_value);
}
这适用于所有对象和阵列:)
ex:
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
这是我对Brian答案的改进版
我使用_has作为属性名称,因为它可能与现有的has属性(例如:maps)冲突
Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=[];
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
needles_square = needles[i].split( "[" );
if(needles_square.length>1){
for( var j = 0; j<needles_square.length; j++ ) {
if(needles_square[j].length){
needles_full.push(needles_square[j]);
}
}
}else{
needles_full.push(needles[i]);
}
}
for( var i = 0; i<needles_full.length; i++ ) {
var res = needles_full[i].match(/^((\d+)|"(.+)"|'(.+)')\]$/);
if (res != null) {
for (var j = 0; j < res.length; j++) {
if (res[j] != undefined) {
needles_full[i] = res[j];
}
}
}
if( typeof obj[needles_full[i]]=='undefined') {
return false;
}
obj = obj[needles_full[i]];
}
return true;
}});
这是小提琴
function propsExists(arg) {
try {
const result = arg()
if (typeof result !== 'undefined') {
return true
}
return false
} catch (e) {
return false;
}
}
此函数还将测试0,null。如果他们在场,它也将返回真实。
例子:
函数propsExists(arg){尝试{常量结果=arg()if(结果类型!==“undefined”){返回true}return false}捕获(e){return false;}}让obj={测试:{a: 空,b: 0,c: 未定义,d: 4中,e: “嘿”,f: ()=>{},g: 5.4中,h: 假,i: 真的,j: {},k: [],我:{a: 1中,}}};console.log('obj.test.a',propsExists(()=>obj.test/a))console.log('obj.test.b',propsExists(()=>obj.test.b))console.log('obj.test.c',propsExists(()=>obj.test.c))console.log('obj.test.d',propsExists(()=>obj.test-d))console.log('obj.test.e',propsExists(()=>obj.test.ex))console.log('obj.test.f',propsExists(()=>obj.test-f))console.log('obj.test.g',propsExists(()=>obj.test/g))console.log('obj.test.h',propsExists(()=>obj.test.h))console.log('obj.test.i',propsExists(()=>obj.test-i))console.log('obj.test.j',propsExists(()=>obj.test.j))console.log('obj.test.k',propsExists(()=>obj.test.k))console.log('obj.test.l',propsExists(()=>obj.test/l))
使现代化
看起来lodash已经为您的所有嵌套属性获取需求添加了_.get。
_.get(countries, 'greece.sparta.playwright')
https://lodash.com/docs#get
上一个答案
lodash用户可能喜欢lodash.contrib,它有几种方法可以缓解这个问题。
获取路径
签名:_.getPath(obj:Object,ks:String|Array)
基于所描述的路径获取嵌套对象中任何深度处的值给出的钥匙。键可以以数组或点分隔字符串的形式给出。如果无法到达路径,则返回undefined。
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined