Bei einem verschachtelten Objekt wie diesem:
var cars = {
"bentley": {
"suppliers": [
{
"location": "England",
"name": "Sheffield Mines"}
]
// ...
}
};
Und in einem Array wie diesem ["bentley", "suppliers", "0", "name"]
gibt es eine vorhandene Funktion, die das tiefste Element, d. h. pluck_innards(cars, ['bentley', "suppliers", "0", "name"])
, zupft und "Sheffield Mines" zurückgibt.
Mit anderen Worten, gibt es eine Funktion (die ich deep_pluck
nennen werde) wo
deep_pluck(cars, ['bentley', 'suppliers', '0', 'name'])
=== cars['bentley']['suppliers']['0']['name']
Es scheint mir, dass dies einfach und doch häufig genug ist, um wahrscheinlich in einer der Javascript-Dienstprogrammbibliotheken wie jQuery oder lo-dash / unterstreichen - aber ich habe es nicht gesehen.
Mein Gedanke ist etwas Triviales in der Art von:
function deep_pluck(array, identities) {
var this_id = identities.shift();
if (identities.length > 0) {
return deep_pluck(array[this_id], identities);
}
return array[this_id];
}
Was ich auf jsFiddle gepostet habe.
Es wäre natürlich hilfreich, wenn die Funktion intelligent genug wäre, um zu identifizieren, wann numerische Indizes in Arrays benötigt werden. Ich bin mir nicht sicher, welche anderen Vorbehalte ein Problem darstellen könnten.
Dies ist alles eine ziemlich lange Frage für etwas, von dem ich mir vorstelle, dass es bereits geschickt gelöst wurde, aber ich dachte, dies zu posten, da ich daran interessiert wäre, zu sehen, welche Lösungen es gibt.
4 Antworten
Ich glaube nicht, dass Sie Probleme mit Array-Indizes haben werden, wenn Sie sie als Nummer 0
übergeben.
Hier ist eine alternative Version Ihrer Funktion ohne Rekursion:
function deep_pluck(object, identities) {
var result = object;
for(var i = 0; i < identities.length; i++) {
result = result[identities[i]];
}
return result;
}
Arbeitsbeispiel hier: http://jsfiddle.net/AmH2w/1/
Obwohl es sich nicht um eine generische Bibliothek handelt, scheint CasperJS mit seinem utils.getPropertyPath
Funktion.
/**
* Retrieves the value of an Object foreign property using a dot-separated
* path string.
*
* Beware, this function doesn't handle object key names containing a dot.
*
* @param Object obj The source object
* @param String path Dot separated path, eg. "x.y.z"
*/
function getPropertyPath(obj, path) {
if (!isObject(obj) || !isString(path)) {
return undefined;
}
var value = obj;
path.split('.').forEach(function(property) {
if (typeof value === "object" && property in value) {
value = value[property];
} else {
value = undefined;
}
});
return value;
}
Bearbeiten:
Ich bin seitdem ein paar Mal auf Implementierungen gestoßen, um dies zu lösen, einschließlich:
Bearbeiten (2014)
Ich würde auch die relativ neue lodash.deep
beachten.
Dotty.get (obj, pathspec) führt dies aus und akzeptiert entweder ein Array oder eine gepunktete Zeichenfolge als Pfadspezifikation.
Dotty ist Open Source und verfügt über eine vorhandene Methode und einen Putter.
Die Methode ist rekursiv und Ihrer Idee sehr ähnlich, außer dass dotty einen Test für null / undefinierte Objekte enthält, damit keine Ausnahmen für den Versuch ausgelöst werden, auf ein Element von etwas zuzugreifen, das nicht existiert.
Die dotty.get () -Quelle aus den Dokumenten ist unten aufgeführt:
var get = module.exports.get = function get(object, path) {
if (typeof path === "string") {
path = path.split(".");
}
if (!(path instanceof Array) || path.length === 0) {
return;
}
path = path.slice();
var key = path.shift();
if (typeof object !== "object" || object === null) {
return;
}
if (path.length === 0) {
return object[key];
}
if (path.length) {
return get(object[key], path);
}
};
Hier ist eine kurze ES6-Implementierung mit reduce
:
function get(obj, keyPath) {
return keyPath
.split(".")
.reduce((prev, curr) => prev[curr], obj);
}
Verwendung:
get(cars, "bentley.suppliers.0.name") // -> "Sheffield Mines"