通常,如果我想检查obj.foo.bar
是否退出,我会这样做:
if(
typeof obj != "undefined" &&
typeof obj.foo !== "undefined" &&
typeof obj.foo.bar !== "undefined"
){ action() }
这是非常丑陋和重复的,遗憾的是我必须经常使用它。
我相信没有任何函数isDefined()
可以这样做,因为即使是空函数(function isDefined(){}
)也会在if(isDefined(obj.foo.bar)){action()}
那么,有没有聪明的方法来检查obj.foo.bar
退出?
编辑:
typeof obj != "undefined"
可以替换为obj
。这个解决方案仍然不能让我满意。编辑2 - 解决方案:
建议here
var a = {
b: {
c: 'd'
}
};
function isDefined(fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isDefined(function () { return a.b.c; }), //return true
isDefined(function () { return a.b.c.d.e.f; }) //returns false
);
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
我已批准@ T.J.克劳德的解决方案,而不是@ somethinghere的解决方案,因为最终常规解决方案更短,并且因为try
catch
语句有其他目的并且可能导致问题
答案 0 :(得分:4)
你可以减少丑陋,因为大部分都不需要typeof
:
if (obj && obj.foo && typeof obj.foo.bar !== "undefined") {
action();
}
如果 obj.foo.bar
不能是假名(0
,""
,NaN
,null
,{{1} },或undefined
),您最后一项不需要false
:
typeof
如果你真的想要一个if (obj && obj.foo && obj.foo.bar) {
action();
}
函数,你必须进入字符串解析as outlined in this other question and its answers,但如果你使用一个重命名(缩短)属性名称的minifier,这可能是一个问题,并且确实涉及字符串解析。
答案 1 :(得分:1)
你实际上可以将它作为一个通用功能:
function isDefined(base){
// Run through any number of passed arguments, ignoring the first one (`base`)
for(var i = 1; i < arguments.length; i++){
// While running, see if they exist and assign it to base, then continue
base = typeof base[arguments[i]] != "undefined"
? base[arguments[i]] : null;
// if base is set to false break the loop as theres nothing deeper to find
if(!base) break;
}
// return the value that base was set to
return base;
}
然后像这样称呼它:
var bar = {foo: {}};
console.log(isDefined(bar, 'foo')); ///= Will be bar[foo] (Object Object)
console.log(isDefined(bar, 'foo', 't')); // Will be 'null'
您将始终必须传递一个参数才能使其工作,但如果您想要全局存在,则可以传递窗口对象。
function isDefined(base){
for(var i = 1; i < arguments.length; i++){
base = typeof base[arguments[i]] != "undefined"
? base[arguments[i]] : null;
if(!base) break;
}
return base;
}
var bar = {foo: {}};
document.write(isDefined(bar, 'foo') + " / " + isDefined(bar, 'foo', 't'));
&#13;
如果您想先查看bar
是否存在,请尝试使用isDefined(window, 'bar', 'foo');
我注意到设置为false
的值也将返回false,因此null是我们的救星。
由于你提出了minifier问题,有一种方法是半优雅的,允许单行部署,但你不能将它包装在一个函数中:
var bar = {};
try { var defined = typeof bar.foo !== "undefined"; } catch(e) { var defined = false; } // defined will be false
var bar = {foo:{}};
try { var defined = typeof bar.foo !== "undefined"; } catch(e) { var defined = false; } // defined will be true
令人讨厌的是它需要在你的if之前执行,但它确实简化了你的if
:
var bar = {};
try { var defined = typeof bar.foo !== "undefined"; } catch(e) { var defined = false; }
if(defined){
// Code here
}
希望有所帮助。
毕竟有一种方法可以将它包装在一个函数中,隐藏得非常深,但这里是被低估的答案的直接链接:javascript test for existence of nested object key
关键是将值包装在一个返回当时值的函数中。它非常聪明!
答案 2 :(得分:0)
这样的事情可以解决问题:
function isDefined(obj, keysString) {
//get all the keys
var keys = keysString.split('.');
var tmp = obj;
for(var i = 0; i < keys.length; i++) {
tmp = tmp[keys[i]];
//slowly construct your 'deep' object while checking if you can
if(typeof tmp === 'undefined') {
return false;
}
}
return true;
}
用法:
isDefined({test: {nested: true}}, 'test.nested'); //return true
isDefined({test: {nested: true}}, 'test.nested.supernested'); //return false
isDefined({test: {nested: true}}, 'test.othernested.supernested'); //return false
小心可能会更改按键名称的缩小器。