从字符串引用Javascript对象
Reference Javascript object from string
给定的数据类似于:
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()?
理想的解决方案是首先不使用字符串表示。认真地问自己是否更改了现有的代码以使您的内容在更理想的输出中
然而,如果你不能,这应该做你想要的:
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
必须在全局作用域中才能工作(不能是局部变量)这是讨厌的。
Edit:要使用设置功能,您可以像下面这样滥用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()
函数检索该对象引用。然后将返回的对象键设置为所需的值。如果我们不这样做,我们就会设置一个值而不是一个引用,所以"真正的"对象永远不会被更新。
Matt的解决方案是纯粹的天才-但是还有一些改进的空间:
- 如果'path'没有分隔符,解决方案失败;
set('h1', somevalue)
将失败,因为在这种情况下,路径分割失败 - 只支持全局作用域
- 如果你有一个具有
obj.here.is.a.value = "I am a value"
的对象,并且你请求obj.here.is.a.value.no.value
-它仍然会返回"I am a 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') )
我不确定我是否理解这个问题,但我猜你想在内部数组中"选择"该对象?
如果是这种情况,你需要循环遍历那个内部数组。
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;
}
}
如果我回答错了,很抱歉占用你的时间:-)
如果您使用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]);
}
}
对于一些懒惰的速记来说,这是一个很大的膨胀。
- 面向对象JavaScript中的私有函数
- 对象 Javascript 中的标签无效 - 想要添加事件列表器
- 将字符串转换为对象 javascript/jquery
- 正在检查对象javascript中是否存在嵌套属性
- 时间-日期对象JavaScript getUTCMilliseconds
- 仅在对象(javascript)中解析值
- 使用对象(JavaScript或jQuery)填充选择下拉列表
- 引用另一个对象javascript中的对象
- 如何删除列表中的对象?Javascript nodejs和下划线
- 无法从日期对象javascript获取日期和月份
- 如何在if语句中使用对象-Javascript
- 对象javascript错误
- 对象Javascript的少数实例
- 位置对象Javascript
- 将字符串传递到对象javascript中
- 获取对象Javascript或jQuery的最后一个值
- 鼠标接近对象Javascript
- 这个mixins代码是书中的错误吗;面向对象JavaScript的原理”;
- 使用闭包编译器编写更好的面向对象JavaScript完整示例代码
- 访问对象javascript数组中的对象属性值