鉴于类似的数据:
var data = [{id: 12345,
name:'my products',
items:[{
size: 'XXL',
sku: 'awe2345',
prices:[{type: 'rrp',prices: 10.99},
{type: 'sell_price', price: 9.99},
{type:'dealer', price:4.50}
]
},{
size: 'XL',
sku: 'awe2346',
prices:[{type: 'rep', prices: 10.99},
{type: 'sell_price', price: 9.99},
{type:'dealer', price:4.50}
]
}
]
}]
}]
有没有办法评估数据对象中元素的字符串表示?例如:“data [0] .items [0] .prices [0] .rrp”...不使用eval()?
答案 0 :(得分:4)
理想的解决方案是首先没有字符串表示。 严重 问问自己,您是否更改了现有代码,以便在更理想的输出中为您提供内容。
但是,如果你不能,这应该做你想要的:
var path = "data[0].items[0].prices[0].rrp".split(/[\[\]\.]+/);
var next = window;
if (path[path.length - 1] == "") {
path.pop();
};
while (path.length && (next = next[path.shift()]) && typeof next == "object" && next !== null);
next;
为此创建一个函数:
function get(path) {
var next = window;
path = path.split(/[\[\]\.]+/);
if (path[path.length - 1] == "") {
path.pop();
};
while (path.length && (next = next[path.shift()]) && typeof next === "object" && next !== null);
return path.length ? undefined : next;
}
缺点:
变量data
必须位于全局范围内才能工作(不能是局部变量)。
这很邋..将它作为最后的手段使用。
编辑:要使用设置功能,您可以滥用JavaScript对象的传递引用性质,如下所示:
function set(path, value) {
var split = Math.max(path.lastIndexOf("["), path.lastIndexOf("."));
get(path.slice(0, split))[path.slice(split + 1).replace(/\]/, "")] = value;
}
提供有关其工作原理的一些解释:
getter 首先将输入拆分为数组,以便每个元素都是我们需要遍历[data, 0, items, 0, prices, 0, rrp]
的成员。如果搜索字符串以“]”结尾,我们会在数组末尾获得一个额外的空元素,因此我们检查并删除它。
然后我们做了大循环;所以我们有遍历的元素(while path.length
),将next
变量设置为我们需要遍历的下一个对象成员next = next[path.shift()]
。检查它是否为对象(否则它将没有任何成员遍历),并检查它是否为null(因为typeof null ==“object”)。
循环执行完毕后,我们将拥有链中的最后一个元素;所以回来吧。
setter 搜索搜索字符串中的最后一个对象引用,并使用get()
函数检索该对象引用。然后,它将返回的对象键设置为所需的值。如果我们没有这样做,我们一直在设置一个值而不是一个引用,所以“真正的”对象永远不会更新。
答案 1 :(得分:4)
马特的解决方案是纯粹的天才 - 但是还有一些改进空间:
set('h1', somevalue)
将失败,因为在这种情况下路径的拆分失败obj.here.is.a.value = "I am a value"
并且您要求obj.here.is.a.value.no.value
- 它仍会返回“我是一个值”以下是我对这三个问题的解决方法:
getPropertyValueByPath : function(obj, path)
{
path = path.split(/[\[\]\.]+/);
if(path[path.length - 1] == "")
{
path.pop();
};
while(path.length && ( obj = obj[path.shift()]));
return obj;
}
setPropertyValuebyPath : function(obj, path, value)
{
var pathElements = path.replace(/\[|\]/g, '.').replace(/\.+/g, '.').split(/\./)
pathEnd = pathElements[pathElements.length - 1]
pathRoot = (pathElements.slice(0, pathElements.length - 1).join('.'))
var currObj = obj
for(var i = 0; i < pathElements.length; i++)
{
if( typeof (currObj[pathElements[i]]) == 'undefined')
{
currObj[pathElements[i]] = {}
}
currObj = currObj[pathElements[i]]
}
// This line by Matt is genious :)
getPropertyValueByPath(obj, pathRoot)[pathEnd] = value
return true
}
像这样打电话给他们:
var joe = {}
setPropertyValueByPath(joe,'the[1].long.and[2].road', 'yeah')
// joe.the[1].long.and[2].road now has a value of 'yeah' -
// all the missing objects were created
// this will alert 'yeah'
alert( getPropertyValueByPath(joe,'the[1].long.and[2].road') )
答案 2 :(得分:0)
我不确定我是否理解这个问题,但我想你想在内部数组中“选择”该对象?
如果是这种情况,则需要遍历该内部数组。
Object.keys( data[0].items[0].prices[0] ).some(function( obj ) {
if( obj.type === 'rrp' ) {
// do something with that object here
return true;
}
});
要使代码符合ES3,我们会选择:
var target = data[0].items[0].prices[0],
len = target.length;
for(var i = 0; i < len; i++) {
if( target[i].type === 'rrp' ) {
// do something with target[i]
break;
}
}
如果我的问题出错了,请为你的时间抱歉: - )
答案 3 :(得分:0)
如果你使用getter而不是暴露的公共字段,你可以在第一次返回集合之前进行一些后处理:
var data = [{
id: 12345,
name: 'my products',
items: [{
size: 'XXL',
sku: 'awe2345',
prices: [{ type: 'rrp', price: 10.99 },
{ type: 'sell_price', price: 9.99 },
{ type: 'dealer', price: 4.50 }
]
}, {
size: 'XL',
sku: 'awe2346',
prices: [{ type: 'rep', price: 10.99 },
{ type: 'sell_price', price: 9.99 },
{ type: 'dealer', price: 4.50}]
}
],
getItems: function () {
if (!this._applied) {
this._applied = true;
for (var i = 0; i < this.items.length; i++) {
this.items[i].prices = this._asCrossReferencable(this.items[i].prices);
}
}
return this.items;
},
_asCrossReferencable: function (priceArr) {
for (var i = 0; i < priceArr.length; i++) {
priceArr[i][priceArr[i].type] = priceArr[i].price;
}
return priceArr;
},
_applied: false
}];
var items = data[0].getItems();
for(var i = 0; i < items.length; i++) {
for(var p = 0; p < items[i].prices.length; p++){
var price = items[i].prices[p];
alert(price[price.type]);
}
}
虽然仅仅是为了一些懒惰的速记,但这是一个很大的膨胀。