Javascript 使用点符号字符串访问对象子属性
我暂时被一个看似非常简单的JavaScript问题所困扰,但也许我只是缺少了正确的搜索关键字 假设我们有一个目标Javascript 使用点符号字符串访问对象子属性,javascript,jquery,Javascript,Jquery,我暂时被一个看似非常简单的JavaScript问题所困扰,但也许我只是缺少了正确的搜索关键字 假设我们有一个目标 var r = { a:1, b: {b1:11, b2: 99}}; 有几种方法可以访问99: r.b.b2 r['b']['b2'] 我想要的是能够定义一个字符串 var s = "b.b2"; 然后使用 r.s or r[s] //(which of course won't work) 一种方法是为它编写一个函数,在点上拆分字符串,并可能递归/迭代地获取属性。但是有没
var r = { a:1, b: {b1:11, b2: 99}};
有几种方法可以访问99:
r.b.b2
r['b']['b2']
我想要的是能够定义一个字符串
var s = "b.b2";
然后使用
r.s or r[s] //(which of course won't work)
一种方法是为它编写一个函数,在点上拆分字符串,并可能递归/迭代地获取属性。但是有没有更简单/更有效的方法?在这里的jQuery API中有什么有用的吗?如果在您的场景中可以将要查找的整个数组变量放入字符串中,则可以使用
eval()
函数
var r = { a:1, b: {b1:11, b2: 99}};
var s = "r.b.b2";
alert(eval(s)); // 99
我能感觉到人们在恐惧中挣扎我不知道支持的jQuery API函数,但我有这个函数:
var ret = data; // Your object
var childexpr = "b.b2"; // Your expression
if (childexpr != '') {
var childs = childexpr.split('.');
var i;
for (i = 0; i < childs.length && ret != undefined; i++) {
ret = ret[childs[i]];
}
}
return ret;
var ret=data;//你的目标
var childexpr=“b.b2”;//你的表情
如果(childexpr!=''){
var childs=childexpr.split('.');
var i;
对于(i=0;i
您也可以这样做
var s = "['b'].b2";
var num = eval('r'+s);
简短回答:不,没有本机的
。访问功能。正如您正确提到的,您必须定义自己的函数来拆分字符串并在其部分上循环/检查
当然,您总是可以使用eval()
像
这是我不久前编写的一个简单函数,但它适用于基本对象属性:
function getDescendantProp(obj, desc) {
var arr = desc.split(".");
while(arr.length && (obj = obj[arr.shift()]));
return obj;
}
console.log(getDescendantProp(r, "b.b2"));
//-> 99
虽然有一些答案将其扩展为“允许”数组索引访问,但这并不是真正必要的,因为您可以使用此方法使用点表示法指定数字索引:
getDescendantProp({ a: [ 1, 2, 3 ] }, 'a.2');
//-> 3
这是我能做的最简单的事情:
var accessProperties = function(object, string){
var explodedString = string.split('.');
for (i = 0, l = explodedString.length; i<l; i++){
object = object[explodedString[i]];
}
return object;
}
var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";
var o = accessProperties(r, s);
alert(o);//99
var accessProperties=函数(对象、字符串){
var explodestring=string.split('.');
对于(i=0,l=explodestring.length;i我扩展了Andy E的答案,因此它也可以处理数组:
function getDescendantProp(obj, desc) {
var arr = desc.split(".");
//while (arr.length && (obj = obj[arr.shift()]));
while (arr.length && obj) {
var comp = arr.shift();
var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp);
if ((match !== null) && (match.length == 3)) {
var arrayData = { arrName: match[1], arrIndex: match[2] };
if (obj[arrayData.arrName] != undefined) {
obj = obj[arrayData.arrName][arrayData.arrIndex];
} else {
obj = undefined;
}
} else {
obj = obj[comp]
}
}
return obj;
}
也许有更有效的方法来处理正则表达式,但它很紧凑
您现在可以执行以下操作:
var model = {
"m1": {
"Id": "22345",
"People": [
{ "Name": "John", "Numbers": ["07263", "17236", "1223"] },
{ "Name": "Jenny", "Numbers": ["2", "3", "6"] },
{ "Name": "Bob", "Numbers": ["12", "3333", "4444"] }
]
}
}
// Should give you "6"
var x = getDescendantProp(model, "m1.People[1].Numbers[2]");
这里有一个比回答更好的方法,如果obj
(上下文)是可选的,如果没有提供,它会返回到窗口
function getDescendantProp(desc, obj) {
obj = obj || window;
var arr = desc.split(".");
while (arr.length && (obj = obj[arr.shift()]));
return obj;
};
扩展@JohnB的答案,我还添加了一个setter值
下面是Andy E代码的扩展,它递归到数组中并返回所有值:
function GetDescendantProps(target, pathString) {
var arr = pathString.split(".");
while(arr.length && (target = target[arr.shift()])){
if (arr.length && target.length && target.forEach) { // handle arrays
var remainder = arr.join('.');
var results = [];
for (var i = 0; i < target.length; i++){
var x = this.GetDescendantProps(target[i], remainder);
if (x) results = results.concat(x);
}
return results;
}
}
return (target) ? [target] : undefined; //single result, wrap in array for consistency
}
我们得到:
GetDescendantProps(t, "a.b.c") === ["x", "z"]; // true
你可以用
获得
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// → 3
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// → 4
设置
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// → 3
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// → 4
Andy E's、Jason More's和我自己的解决方案的性能测试可在上获得。请随时使用您自己的浏览器运行测试,以添加到收集的数据中
预后很清楚,安迪·E的解决方案是目前为止最快的
对于任何感兴趣的人,这里是我解决原始问题的代码
function propertyAccessor(object, keys, array) {
/*
Retrieve an object property with a dot notation string.
@param {Object} object Object to access.
@param {String} keys Property to access using 0 or more dots for notation.
@param {Object} [array] Optional array of non-dot notation strings to use instead of keys.
@return {*}
*/
array = array || keys.split('.')
if (array.length > 1) {
// recurse by calling self
return propertyAccessor(object[array.shift()], null, array)
} else {
return object[array]
}
}
并将对象作为initalValue
var r={a:1,b:{b1:11,b2:99};
var s=“b.b2”;
var值=s.split('.')。reduce(函数(a,b){
返回a[b];
},r);
console.log(value);
+1,用于预测我的卷轴。不幸的是,卷轴问题是使用eval
会阻止编译器进行某些词法优化。这意味着,不仅eval
本身速度慢,还会减慢周围代码的速度。哦……还有双关语。哦,我知道eval()的陷阱
。事实上,我要去洗羊毛浴了,因为我觉得很脏,甚至推荐了它。Andy,我已经+1了你的答案,因为它很容易是这里最优雅的。谢谢,这很简洁-但是根据Andy的评论,我不能承受性能下降,因为脚本做了很多事情。var getObjectValue=函数getter(object,key){var value;如果(typeof object=='object'&&typeof key=='string'){value=eval('object'+'.+key);}返回值;}您可以始终构建字符串并eval()
在需要时使用它,但我认为没有人会认为这是个好主意。按照您描述的方式解析字符串更安全。@jrummell在struts2应用程序中,我使用的是jqgrid,它在列格式化程序中获取rowObject。rowObject对象结构遵循列数据模型,其中包含一些我需要访问的嵌套属性在一个循环中以一种通用的方式。+1,这与我的解决方案非常相似,但有一个显著的区别。如果其中一个属性(最后一个除外)出现错误,您的解决方案将抛出一个错误不存在。我的将返回undefined
。这两种解决方案在不同的场景中都很有用。您只需将正则表达式传递给split
。只需使用desc..split(/[\.\[\]]+/);
并向下循环属性。jshint告诉我重写:while(arr.length){obj=obj[arr.shift()];}@user1912899:这不完全相同,但可能更健壮一些,因为它会抛出错误(而我的将只返回未定义的
)。我想这取决于您的偏好。JSHint只是抱怨循环中的赋值条件,可以使用boss
选项禁用它。您可以执行,而(arr.length&&obj){obj=obj[arr.shift()];}
a[1]不起作用:(@JuanDavid:不,这不像eval语句,它只是一个简单的拆分循环。你可以使用a.1
,除非你有一些名称中带有“.”的属性。如果是这样的话,你需要一个更复杂的解决方案。我试图调整Andy E的解决方案以获得一个集合,然后我向下滚动找到了这个。插入这个函数n进入,看着我所有的测试都变成绿色。谢谢。谢谢你添加了集合功能。ES6语法更简短:let value=
function propertyAccessor(object, keys, array) {
/*
Retrieve an object property with a dot notation string.
@param {Object} object Object to access.
@param {String} keys Property to access using 0 or more dots for notation.
@param {Object} [array] Optional array of non-dot notation strings to use instead of keys.
@return {*}
*/
array = array || keys.split('.')
if (array.length > 1) {
// recurse by calling self
return propertyAccessor(object[array.shift()], null, array)
} else {
return object[array]
}
}