javascript - Åtkomst till objektets barnegenskaper med hjälp av en sträng i punktnotation
Jag sitter tillfälligt fast med vad som verkar vara ett mycket enkelt JavaScript-problem, men kanske saknar jag bara rätt sökord!
Säg att vi har ett objekt
var r = { a:1, b: {b1:11, b2: 99}};
Det finns flera sätt att få tillgång till 99:
r.b.b2
r['b']['b2']
Det jag vill är att kunna definiera en sträng
var s = "b.b2";
och sedan komma åt 99 med
r.s or r[s] //(which of course won't work)
Ett sätt är att skriva en funktion för det som delar upp strängen på punkt och kanske rekursivt/iterativt hämtar egenskapen. Men finns det något enklare/mer effektivt sätt? Finns det något användbart i någon av jQuery APIs här?
Svar #1
Här är en naiv funktion jag skrev för ett tag sedan, men den fungerar för grundläggande objekt-egenskaper:
function getDescendantProp(obj, desc) {
var arr = desc.split(".");
while(arr.length && (obj = obj[arr.shift()]));
return obj;
}
console.log(getDescendantProp(r, "b.b2"));
//-> 99
Även om det finns svar som utvidgar detta till att "tillåta" åtkomst till array-index, är det egentligen inte nödvändigt eftersom du bara kan specificera numeriska index med punktnotation med denna metod:
getDescendantProp({ a: [ 1, 2, 3 ] }, 'a.2');
//-> 3
Svar #2
split och reduce medan objektet skickas som initalValue
Uppdatering (tack till kommentaren från TeChn4K)
Med ES6-syntax är det ännu kortare
var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";
var value = s.split('.').reduce((a, b) => a[b], r);
console.log(value);Gammal version
var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";
var value = s.split('.').reduce(function(a, b) {
return a[b];
}, r);
console.log(value);Svar #3
Du kan använda lodash get() och set() metoder.
Får
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// → 3
Inställning
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// → 4
Svar #4
Om det är möjligt i ditt scenario att du kan sätta hela array-variabeln du är ute efter i en sträng, kan du använda eval()-funktionen.
var r = { a:1, b: {b1:11, b2: 99}};
var s = "r.b.b2";
alert(eval(s)); // 99
Jag kan känna människor rygga tillbaka i skräck
Svar #5
Förlänger @JohnB:s svar, jag lade också till ett inställningsvärde. Kolla in plunkern på
http://plnkr.co/edit/lo0thC?p=preview
function getSetDescendantProp(obj, desc, value) {
var arr = desc ? desc.split(".") : [];
while (arr.length && obj) {
var comp = arr.shift();
var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp);
// handle arrays
if ((match !== null) && (match.length == 3)) {
var arrayData = {
arrName: match[1],
arrIndex: match[2]
};
if (obj[arrayData.arrName] !== undefined) {
if (typeof value !== 'undefined' && arr.length === 0) {
obj[arrayData.arrName][arrayData.arrIndex] = value;
}
obj = obj[arrayData.arrName][arrayData.arrIndex];
} else {
obj = undefined;
}
continue;
}
// handle regular things
if (typeof value !== 'undefined') {
if (obj[comp] === undefined) {
obj[comp] = {};
}
if (arr.length === 0) {
obj[comp] = value;
}
}
obj = obj[comp];
}
return obj;
}
