在javascript中,假设我想访问对象深处的属性,例如:
entry.mediaGroup [0] .contents [0] .URL
在该结构的任何位置,属性可能未定义(因此可能未设置mediaGroup)。
简单的说法是什么:
if( entry.mediaGroup[0].contents[0].url ){
console.log( entry.mediaGroup[0].contents[0].url )
}
没有产生错误?如果未定义任何一点,这种方式将产生一个未定义的错误。
我的解决方案
if(entry) && (entry.mediaGroup) && (entry.MediaGroup[0]) ...snip...){
console.log(entry.mediaGroup[0].contents[0].url)
}
非常冗长。我猜想必须有更优雅的东西。
答案 0 :(得分:7)
这是一种非常懒惰的方法,但它符合许多类似情况的标准:
try {
console.log(entry.mediaGroup[0].contents[0].url);
} catch (e) {}
这不应该在可能会忽略其他错误的长代码块上完成,但应该适用于这样的简单情况。
答案 1 :(得分:3)
/*decend through an object tree to a specified node, and return it.
If node is unreachable, return undefined. This should also work with arrays in the tree.
Examples:
var test1 = {a:{b:{c:{d:1}}}};
console.log(objectDesend(test1, 'a', 'b', 'c', 'd'));
var test2 = {a:{b:{c:1}}}; //will fail to reach d
console.log(objectDesend(test2, 'a', 'b', 'c', 'd'));
*/
var objectDescend = function(){
var obj = arguments[0];
var keys = arguments;
var cur = obj;
for(var i=1; i<keys.length; i++){
var key = keys[i];
var cur = cur[key];
if(typeof(cur)=='undefined')
return cur;
}
return cur;
}
var test1 = {a:{b:{c:{d:1}}}};
console.log(objectDescend(test1, 'a', 'b', 'c', 'd'));
var test2 = {a:{b:{c:1}}};
console.log(objectDescend(test2, 'a', 'b', 'c', 'd'));
因此,这将返回您要查找的值,或者由于该值不存在而未定义。它不会返回false,因为它实际上可能是您正在寻找的值(d:false)。
在我的代码库中,我添加了Object.prototype.descend,因此我可以执行test1.descend('a','b','c','d')。这只适用于ECMAScript 5(IE&gt; = 9),因为你需要这样做才能使你的函数不出现在枚举中。欲了解更多信息: Add a method to Object primative, but not have it come up as a property
这是我的代码:
Object.defineProperty(Object.prototype, 'descend', {
value: function(){
var keys = arguments;
var cur = this;
for(var i=0; i<keys.length; i++){
var key = keys[i];
var cur = cur[key];
if(typeof(cur)=='undefined')
return cur;
}
return cur;
}
});
var test1 = {a:{b:{c:{d:false}}}};
//this will return false, which is the value of d
console.log(test1.descend('a', 'b', 'c', 'd'));
var test2 = {a:{b:{c:1}}};
//undefined since we can't reach d.
console.log(test2.descend(test2, 'a', 'b', 'c', 'd'));
答案 2 :(得分:2)
你当前的解决方案可能和你能得到的一样好,正如mVChr所说,try..catch在这里很懒。除了可能更容易键入(但不是那么明显)之外,它可能远没有那么高效,也没有什么可推荐的,而且它会更难调试,因为它会默默地隐藏错误。
真正的问题是通过尝试此类访问而创建的非常长的“参考蠕虫”。至少减少属性查找次数的原始替代方法是:
var o;
if ( (o = entry ) &&
(o = o.mediaGroup) &&
(o = o[0] ) &&
(o = o.contents ) &&
(o = o[0] )) {
alert(o.url);
}
但我希望你不会那样。
如果您有许多此类深层访问路径,您可能希望创建一个函数来执行访问,并在成功时返回最后一个对象,或者在失败时返回其他一些vaule。如果失败,您还可以让它返回路径上的最后一个非假名对象。
// Create test object
var entry = {};
entry.mediaGroup = [{
contents: [{url: 'url'}]
}];
// Check that it "works"
// alert(entry.mediaGroup[0].contents[0].url);
// Deep property access function, returns last object
// or false
function deepAccess(obj) {
var path = arguments;
var i = 0, iLen = path.length;
var o = path[i++]; // o is first arg
var p = path[i++]; // p is second arg
// Go along path until o[p] is falsey
while (o[p]) {
o = o[p];
p = path[i++];
}
// Return false if didn't get all the way along
// the path or the last non-falsey value referenced
return (--i == iLen) && o;
}
// Test it
var x = deepAccess(entry, 'mediaGroup','0','contents','0');
alert(x && x.url); // url
var x = deepAccess(entry, 'mediaGroup','1','contents','0');
alert(x && x.url); // false
答案 3 :(得分:2)
这种情况下可能存在3-4个不同的问题,答案数量是答案的4倍。他们都没有真正满足我,所以我自己做了,我会分享它。
此功能被称为&#34; deepGet&#34;。
示例:的
deepGet(mySampleData, "foo.bar[2].baz", null);
以下是完整代码:
function deepGet (obj, path, defaultValue) {
// Split the path into components
var a = path.split('.');
// If we have just one component left, note that for later.
var last = (a.length) === 1;
// See if the next item is an array with an index
var myregexp = /([a-zA-Z]+)(\[(\d+)\])+/; // matches: item[0]
var match = myregexp.exec(a[0]);
// Get the next item
var next;
if (match !== null) {
next = obj[match[1]];
if (next !== undefined) {
next = next[match[3]];
}
} else {
next = obj[a[0]];
}
if (next === undefined || next === null) {
// If we don't have what we want, return the default value
return defaultValue;
} else {
if (last) {
// If it's the last item in the path, return it
return next;
} else {
// If we have more items in the path to go, recurse
return deepGet (next, a.slice(1).join("."), defaultValue);
}
}
}
这是一个jsFiddle:http://jsfiddle.net/7quzmjh8/2/
我受到这两件事的启发:
http://designpepper.com/blog/drips/making-deep-property-access-safe-in-javascript.html http://jsfiddle.net/wxrzM/1/
希望这对那里的人有用:)
答案 4 :(得分:0)
我使用这个简单的函数来玩深层对象属性:
getProperty = function(path) {
try {
return eval(path);
}
catch (e) {
return undefined;
}
};
以下是一个例子:
var test = {a:{b:{c:"success!"}}};
alert(getProperty('test.c.c'));
// undefined
alert(getProperty('test.a.b.c'));
// success!
答案 5 :(得分:-1)
这是我已经使用了一段时间
var obj = { a: { b: [
{ c: {d: 'XYZ'} }
] } };
// working
obj.a.b[0].c.d = null;
console.log('value:'+getProperty(obj, 'a.b[0].c.d', 'NOT-AVAILABLE')); // value:null
obj.a.b[0].c.d = 'XYZ';
console.log('value:'+getProperty(obj, 'a.b[0].c.d', 'NOT-AVAILABLE')); // value:XYZ
console.log('value:'+getProperty(obj, 'a.b[0].c.d.k.sds', 'NOT-AVAILABLE')); // value:NOT-AVAILABLE
obj.a.b[0].c = null;
console.log('value:'+getProperty(obj, 'a.b[0].c.d', 'NOT-AVAILABLE')); // value:NOT-AVAILABLE
// will not work
//console.log('v:'+getProperty(obj, 'a.b["0"].c.d'));
这是函数
function getProperty(obj, str, defaultValue){
var props = str.split('.').map(function(prop){
var arrAccessRegEx = /(.*)\[(.*)\]/g;
if (arrAccessRegEx.test(prop)){
return prop.split(arrAccessRegEx).filter(function(ele){return ele!=''; });
} else {
var retArr = [];
retArr.push(prop);
return retArr
};
});
//console.log(props);
for(var i=0;i<props.length;i++){
var prop = props[i][0];
//console.log('prop:'+prop);
if (obj === null) return defaultValue;
obj = obj[prop];
if (obj === undefined) return defaultValue;
if (props[i].length == 2){
var idx = props[i][1];
if (!(obj instanceof Array)) return defaultValue;
if (idx < obj.length ){
obj = obj[idx];
if (obj === undefined) return defaultValue;
}
}
} // for each item in split
return obj;
}