我正在使用一个大型的Javascript代码库,目前乱七八糟的代码依赖于流量控制的异常
function getChecklistUrl() {
try {
return dataLayerObject.config.checklist;
} catch (e) {
try {
console.error('dataLayer', e);
} catch (ignore) {}
}
}
我可能更喜欢条件逻辑,例如同一函数的实现
function getChecklistUrl() {
if(typeof dataLayerObject == 'object' &&
'config' in dataLayerObject &&
typeof dataLayerObject.config == 'object' &&
'checklist' in dataLayerObject.config &&
typeof dataLayerObject.config.checklist == 'object') {
return dataLayerObject.config.checklist;
}
return null;
}
虽然后者感觉很长,但是当然可以编写辅助函数来减少这种检查的样板。
前者是Javascript的惯用语吗?后来是脆弱的(跨越浏览器/场景),最好还是留给try
/ catch
吗?或者前者只是懒惰的证据?
修改
这些对象被认为是“普通”对象,例如var obj = {}
所以我不相信我在这里关心原型链。
答案 0 :(得分:6)
在javascript中检查对象属性的正确方法是Object.hasOwnProperty()方法。
示例:
var Person = {
first_name: 'Fred',
last_name: 'Flintstone'
};
if ( 'object' === typeof Person && Person.hasOwnProperty('first_name' ) {
window.alert('the property exists!');
}
修改强>
要检查嵌套对象属性,可以尝试这样的方法:
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
答案 1 :(得分:2)
首先,您不需要同时检查 property in object
&amp;&amp; typeof obj[property] == 'object'
,您只能使用typeof
来处理这两项检查。原因是,如果obj.property
不存在,typeof
将返回undefined
。
因此,您可以通过编写一个小实用程序函数来模块化您的方法,该函数检查某些东西是否为对象:
function isObject(o) {
return typeof o == 'object' && o !== null; // take care of the corner case that typeof null == 'object'
}
然后只需在必要的对象链上使用它,通过检查所有拥有的对象是否存在来查找属性:
function getChecklistUrl() {
if(isObject(dataLayerObject) &&
isObject(dataLayerObject.config) &&
isObject(dataLayerObject.config.checklist)) {
return dataLayerObject.config.checklist;
}
return null;
}
var dataLayerObject = {
config: {
checklist: ['array of stuff']
}
}
function isObject(o) {
return typeof o == 'object' && o !== null;
}
function getChecklistUrl() {
if (isObject(dataLayerObject) &&
isObject(dataLayerObject.config) &&
isObject(dataLayerObject.config.checklist)) {
return dataLayerObject.config.checklist;
}
return null;
}
console.log(getChecklistUrl()[0]);
这使代码更有条理,更容易阅读,恕我直言。
你也可以为你的对象做一个像getter一样的东西,它取一个点分隔的字符串并返回你的属性,如果属性不存在,你也可以为null:
function getObjProperty(obj, propString) {
if(!isObject(obj) || !propString || typeof propString != 'string') {
return null; // make sure obj is an object and propString is a non-empty string
}
var props = propString.split('.');
for (var i = 0, l = props.length; i < l; i++) {
var p = props[i];
if(!isObject(obj[p])) { return null; } // if current property isn't an object, return null
obj = obj[p]; // otherwise update the object to the next one down the property chain
}
return obj;
}
您可以使用它:getObjProperty(dataLayerObject, 'config.checklist');
var dataLayerObject = {
config: {
checklist: ['array of stuff']
}
};
function isObject(o) {
return typeof o == 'object' && o !== null;
}
function getObjProperty(obj, propString) {
if (!isObject(obj) || !propString || typeof propString != 'string') {
return null;
}
var props = propString.split('.');
for (var i = 0, l = props.length; i < l; i++) {
var p = props[i];
if (!isObject(obj[p])) { //
return null;
} // if current property isn't an object, return null
obj = obj[p]; // otherwise update the object to the next one down the property chain
}
return obj;
}
console.log(getObjProperty(dataLayerObject, 'config.checklist'));
或者您可以使用fairly straightforward recursive method
来实现此目的注意强>:
上面的例子也检查了原型链。如果您不想这样做,则在检查属性是否为对象时应使用hasOwnProperty
来检查测试对象上是否存在该属性。
Prefix's answer显示了这种方法的一种变体。
答案 2 :(得分:0)
如果你希望它很短,你可以做这样的事情,但它不会检查dataLayer是否是一个对象,所以如果它是一个带有配置和清单的函数,它也会返回它。但由于它是一个自定义对象,它可能不是一个问题。如果需要,您可以添加“in”或“hasOwnProperty”检查,如果您愿意,可以使用三元组。
var getChecklistUrl = function getChecklistUrl() {
return dataLayerObject && dataLayerObject.config && dataLayerObject.config.checklist || null;
}
答案 3 :(得分:0)
您可以通过利用强制转换来缩短它:
if ( typeof dataLayerObject == 'object' &&
dataLayerObject.config &&
dataLayerObject.config.checklist &&
typeof dataLayerObject.config.checklist == 'object') {
// do something
}
如果你真的不想检查清单实际上是一个对象,你可以摆脱最后的typeof
。第一个typeof
是必需的,因为您的变量看起来可能是全局的。