我有一个这样的数据结构:
var someObject = {
'part1' : {
'name': 'Part 1',
'size': '20',
'qty' : '50'
},
'part2' : {
'name': 'Part 2',
'size': '15',
'qty' : '60'
},
'part3' : [
{
'name': 'Part 3A',
'size': '10',
'qty' : '20'
}, {
'name': 'Part 3B',
'size': '5',
'qty' : '20'
}, {
'name': 'Part 3C',
'size': '7.5',
'qty' : '20'
}
]
};
我想使用这些变量访问数据:
var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";
part1name应该用someObject.part1.name的值填充,即“Part 1”。part2quantity也是一样,它的容量是60。
有没有办法实现这与纯javascript或JQuery?
mohamed Hamouday' Answer的扩展将填补缺失的关键
function Object_Manager(obj, Path, value, Action, strict)
{
try
{
if(Array.isArray(Path) == false)
{
Path = [Path];
}
let level = 0;
var Return_Value;
Path.reduce((a, b)=>{
console.log(level,':',a, '|||',b)
if (!strict){
if (!(b in a)) a[b] = {}
}
level++;
if (level === Path.length)
{
if(Action === 'Set')
{
a[b] = value;
return value;
}
else if(Action === 'Get')
{
Return_Value = a[b];
}
else if(Action === 'Unset')
{
delete a[b];
}
}
else
{
return a[b];
}
}, obj);
return Return_Value;
}
catch(err)
{
console.error(err);
return obj;
}
}
例子
obja = {
"a": {
"b":"nom"
}
}
// Set
path = "c.b" // Path does not exist
Object_Manager(obja,path.split('.'), 'test_new_val', 'Set', false);
// Expected Output: Object { a: Object { b: "nom" }, c: Object { b: "test_new_value" } }
数组可以代替字符串来处理嵌套对象和数组,例如:["my_field", "another_field", 0, "last_field", 10]
下面是一个基于该数组表示方式更改字段的示例。我在react.js中使用类似的东西来控制输入字段,改变嵌套结构的状态。
let state = {
test: "test_value",
nested: {
level1: "level1 value"
},
arr: [1, 2, 3],
nested_arr: {
arr: ["buh", "bah", "foo"]
}
}
function handleChange(value, fields) {
let update_field = state;
for(var i = 0; i < fields.length - 1; i++){
update_field = update_field[fields[i]];
}
update_field[fields[fields.length-1]] = value;
}
handleChange("update", ["test"]);
handleChange("update_nested", ["nested","level1"]);
handleChange(100, ["arr",0]);
handleChange('changed_foo', ["nested_arr", "arr", 3]);
console.log(state);
而不是尝试模拟JS语法,你将不得不花费大量的计算解析,或者只是错误/忘记一些事情,比如一堆这些答案(带.s的键,有人吗?),只是使用一个键数组。
var part1name = Object.get(someObject, ['part1', 'name']);
var part2quantity = Object.get(someObject, ['part2', 'qty']);
var part3name1 = Object.get(someObject, ['part3', 0, 'name']);
如果您需要使用单个字符串,只需JSONify它。
此方法的另一个改进是您可以删除/设置根级对象。
function resolve(obj, path) {
let root = obj = [obj];
path = [0, ...path];
while (path.length > 1)
obj = obj[path.shift()];
return [obj, path[0], root];
}
Object.get = (obj, path) => {
let [parent, key] = resolve(obj, path);
return parent[key];
};
Object.del = (obj, path) => {
let [parent, key, root] = resolve(obj, path);
delete parent[key];
return root[0];
};
Object.set = (obj, path, value) => {
let [parent, key, root] = resolve(obj, path);
parent[key] = value;
return root[0];
};
其他功能演示:
对于.set(/.del()的bob =是不必要的,除非你的路径可能是空的(操作根对象)。
我证明我不克隆的对象使用史蒂夫保持原始的引用和检查bob == steve //true后,第一个.set(
这可能永远都不会曝光……但不管怎样,它在这里。
将[]括号语法替换为。
继续前进。字符
删除空白字符串
找到路径(否则未定义)
(为了找到一个对象的路径,使用这个pathTo解决方案。)
// "one liner" (ES6)
const deep_value = (obj, path) =>
path
.replace(/\[|\]\.?/g, '.')
.split('.')
.filter(s => s)
.reduce((acc, val) => acc && acc[val], obj);
// ... and that's it.
var someObject = {
'part1' : {
'name': 'Part 1',
'size': '20',
'qty' : '50'
},
'part2' : {
'name': 'Part 2',
'size': '15',
'qty' : '60'
},
'part3' : [
{
'name': 'Part 3A',
'size': '10',
'qty' : '20'
}
// ...
],
'pa[rt3' : [
{
'name': 'Part 3A',
'size': '10',
'qty' : '20'
}
// ...
]
};
console.log(deep_value(someObject, "part1.name")); // Part 1
console.log(deep_value(someObject, "part2.qty")); // 60
console.log(deep_value(someObject, "part3[0].name")); // Part 3A
console.log(deep_value(someObject, "part3[0].....name")); // Part 3A - invalid blank paths removed
console.log(deep_value(someObject, "pa[rt3[0].name")); // undefined - name does not support square brackets
我只是基于一些类似的代码,我已经有了,它似乎工作:
Object.byString = function(o, s) {
s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
s = s.replace(/^\./, ''); // strip a leading dot
var a = s.split('.');
for (var i = 0, n = a.length; i < n; ++i) {
var k = a[i];
if (k in o) {
o = o[k];
} else {
return;
}
}
return o;
}
用法::
Object.byString(someObj, 'part3[0].name');
在http://jsfiddle.net/alnitak/hEsys/上可以看到一个工作演示
有些人注意到,如果传递的字符串中最左边的索引与对象中正确嵌套的条目不对应,这段代码将抛出错误。这是一个有效的问题,但我认为最好在调用时使用try / catch块来解决,而不是让这个函数对于无效的索引无声地返回undefined。