我有一个这样的数据结构:
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?
/**
* Access a deep value inside a object
* Works by passing a path like "foo.bar", also works with nested arrays like "foo[0][1].baz"
* @author Victor B. https://gist.github.com/victornpb/4c7882c1b9d36292308e
* Unit tests: http://jsfiddle.net/Victornpb/0u1qygrh/
*/
function getDeepVal(obj, path) {
if (typeof obj === "undefined" || obj === null) return;
path = path.split(/[\.\[\]\"\']{1,2}/);
for (var i = 0, l = path.length; i < l; i++) {
if (path[i] === "") continue;
obj = obj[path[i]];
if (typeof obj === "undefined" || obj === null) return;
}
return obj;
}
适用于
getDeepVal(obj,'foo.bar')
getDeepVal(obj,'foo.1.bar')
getDeepVal(obj,'foo[0].baz')
getDeepVal(obj,'foo[1][2]')
getDeepVal(obj,"foo['bar'].baz")
getDeepVal(obj,"foo['bar']['baz']")
getDeepVal(obj,"foo.bar.0.baz[1]['2']['w'].aaa[\"f\"].bb")
基于前面的回答,我创建了一个也可以处理括号的函数。但由于裂开,里面没有点。
function get(obj, str) {
return str.split(/\.|\[/g).map(function(crumb) {
return crumb.replace(/\]$/, '').trim().replace(/^(["'])((?:(?!\1)[^\\]|\\.)*?)\1$/, (match, quote, str) => str.replace(/\\(\\)?/g, "$1"));
}).reduce(function(obj, prop) {
return obj ? obj[prop] : undefined;
}, obj);
}
使用对象扫描,这就变成了一行。然而,更重要的是,这个解决方案考虑性能:
在搜索期间遍历一次输入(即使查询了多个键)
解析只在init上发生一次(如果查询多个对象)
允许使用*进行扩展语法
// const objectScan = require('object-scan');
const 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' }] };
const get = (haystack, needle) => objectScan([needle], { rtn: 'value', abort: true })(haystack);
console.log(get(someObject, 'part1.name'));
// => Part 1
console.log(get(someObject, 'part2.qty'));
// => 60
console.log(get(someObject, 'part3[0].name'));
// => Part 3A
const getAll = (haystack, ...needles) => objectScan(needles, { reverse: false, rtn: 'entry', joined: true })(haystack);
console.log(getAll(someObject, 'part1.name', 'part2.qty', 'part3[0].name'));
/* =>
[ [ 'part1.name', 'Part 1' ],
[ 'part2.qty', '60' ],
[ 'part3[0].name', 'Part 3A' ] ]
*/
console.log(getAll(someObject, 'part1.*'));
/* =>
[ [ 'part1.name', 'Part 1' ],
[ 'part1.size', '20' ],
[ 'part1.qty', '50' ] ]
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>
声明:我是object-scan的作者
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" } }
如果你需要访问不同的嵌套键,而不知道它在编码时(这将是微不足道的),你可以使用数组符号访问器:
var part1name = someObject['part1']['name'];
var part2quantity = someObject['part2']['qty'];
var part3name1 = someObject['part3'][0]['name'];
它们等价于点符号访问器,并且可能在运行时发生变化,例如:
var part = 'part1';
var property = 'name';
var part1name = someObject[part][property];
等于
var part1name = someObject['part1']['name'];
or
var part1name = someObject.part1.name;
我希望这能解决你的问题…
EDIT
我不会使用字符串来维护某种xpath查询来访问对象值。
因为你必须调用一个函数来解析查询和检索值,我会遵循另一条路径(不是:
var part1name = function(){ return this.part1.name; }
var part2quantity = function() { return this['part2']['qty']; }
var part3name1 = function() { return this.part3[0]['name'];}
// usage: part1name.apply(someObject);
或者,如果你不习惯apply方法
var part1name = function(obj){ return obj.part1.name; }
var part2quantity = function(obj) { return obj['part2']['qty']; }
var part3name1 = function(obj) { return obj.part3[0]['name'];}
// usage: part1name(someObject);
函数更短,更清晰,解释器会为你检查语法错误等等。
顺便说一下,我觉得在适当的时候做一个简单的任务就足够了……