我有一个这样的数据结构:
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?
如果您想要一个能够正确检测和报告路径解析的任何问题的详细信息的解决方案,我为此编写了自己的解决方案——库路径-值。
const {resolveValue} = require('path-value');
resolveValue(someObject, 'part1.name'); //=> Part 1
resolveValue(someObject, 'part2.qty'); //=> 50
resolveValue(someObject, 'part3.0.name'); //=> Part 3A
请注意,对于索引,我们使用.0,而不是[0],因为解析后者会增加性能损失,而.0直接在JavaScript中工作,因此非常快。
然而,完整的ES5 JavaScript语法也被支持,它只需要首先被标记化:
const {resolveValue, tokenizePath} = require('path-value');
const path = tokenizePath('part3[0].name'); //=> ['part3', '0', 'name']
resolveValue(someObject, path); //=> Part 3A
AngularJS有$scope.$eval
在AngularJS中,我们可以使用$scope。$eval方法访问嵌套对象:
$scope.someObject = someObject;
console.log( $scope.$eval("someObject.part3[0].name") ); //Part 3A
有关更多信息,请参见
AngularJS $scope API引用- $eval
演示
angular.module("app",[])
.run(function($rootScope) {
$rootScope.someObject = {
'part2' : {
'name': 'Part 2',
'size': '15',
'qty' : '60'
},
'part3' : [{
'name': 'Part 3A',
'size': '10',
'qty' : '20'
},{
name: 'Part 3B'
}]
};
console.log(
"part3[0].name =",
$rootScope.$eval("someObject.part3[0].name")
);
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app"
</body>
/**
* 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")
我只是基于一些类似的代码,我已经有了,它似乎工作:
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。
数组可以代替字符串来处理嵌套对象和数组,例如:["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);