我有一个这样的数据结构:
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 resolve(path, obj=self, separator='.') {
var properties = Array.isArray(path) ? path : path.split(separator)
return properties.reduce((prev, curr) => prev?.[curr], obj)
}
使用示例:
// accessing property path on global scope
resolve("document.body.style.width")
// or
resolve("style.width", document.body)
// accessing array indexes
// (someObject has been defined in the question)
resolve("part3.0.size", someObject) // returns '10'
// accessing non-existent properties
// returns undefined when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})
// accessing properties with unusual keys by changing the separator
var obj = { object: { 'a.property.name.with.periods': 42 } }
resolve('object->a.property.name.with.periods', obj, '->') // returns 42
// accessing properties with unusual keys by passing a property name array
resolve(['object', 'a.property.name.with.periods'], obj) // returns 42
限制:
不能将方括号([])用于数组下标-尽管在分隔符令牌之间指定数组下标(例如,.)可以正常工作,如上所示。
也适用于对象内的数组/数组。
防御无效值。
/**
* Retrieve nested item from object/array
* @param {Object|Array} obj
* @param {String} path dot separated
* @param {*} def default value ( if result undefined )
* @returns {*}
*/
function path(obj, path, def){
var i, len;
for(i = 0,path = path.split('.'), len = path.length; i < len; i++){
if(!obj || typeof obj !== 'object') return def;
obj = obj[path[i]];
}
if(obj === undefined) return def;
return obj;
}
//////////////////////////
// TEST //
//////////////////////////
var arr = [true, {'sp ace': true}, true]
var obj = {
'sp ace': true,
arr: arr,
nested: {'dotted.str.ing': true},
arr3: arr
}
shouldThrow(`path(obj, "arr.0")`);
shouldBeDefined(`path(obj, "arr[0]")`);
shouldBeEqualToNumber(`path(obj, "arr.length")`, 3);
shouldBeTrue(`path(obj, "sp ace")`);
shouldBeEqualToString(`path(obj, "none.existed.prop", "fallback")`, "fallback");
shouldBeTrue(`path(obj, "nested['dotted.str.ing'])`);
<script src="https://cdn.rawgit.com/coderek/e7b30bac7634a50ad8fd/raw/174b6634c8f57aa8aac0716c5b7b2a7098e03584/js-test.js"></script>
这是一个有lodash的单班轮。
const deep = { l1: { l2: { l3: "Hello" } } };
const prop = "l1.l2.l3";
const val = _.reduce(prop.split('.'), function(result, value) { return result ? result[value] : undefined; }, deep);
// val === "Hello"
或者更好……
const val = _.get(deep, prop);
或ES6版本w/ reduce…
const val = prop.split('.').reduce((r, val) => { return r ? r[val] : undefined; }, deep);
普伦克尔