3 回答

TA貢獻1846條經驗 獲得超7個贊
您可以遍歷 中的每個鍵值對對象,以查看哪個鍵屬于當前對象。獲得適用于當前對象的鍵后,您可以訪問其關聯的數組以及需要查看的索引。找到鍵值對后,可以從條目中刪除鍵值對,然后再次以遞歸方式查找新對象中的下一個鍵。您可以繼續此操作,直到找不到屬于當前對象的鍵(即:findIndex返回-1);menuIndexespathToParsemenuIndexesdata
const pathToParse = { buildings: [ { name: 'office', building_styles: [ { name: 'interior', rooms: [ { name: 'open space', filling_types: [ { name: 'furniture', inventories: [{ id: 1, name: 'tv' }, { id: 2, name: 'chair' }, { id: 3, name: 'table' }, ] } ] } ] }, ] }, ] }
const menuIndexes = {
buildings: 0,
building_styles: 0,
rooms: 0,
room_fillings: 0,
filling_types: 0,
}
function getPath(data, entries) {
const keyIdx = entries.findIndex(([key]) => key in data);
if(keyIdx <= -1)
return [];
const [objKey, arrIdx] = entries[keyIdx];
const obj = data[objKey][arrIdx];
entries.splice(keyIdx, 1);
return [obj.name].concat(getPath(obj, entries));
}
console.log(getPath(pathToParse, Object.entries(menuIndexes)));
的用途是搜索對象以查找要查看的鍵(因為我們不想依賴于對象的鍵排序)。如果您對 有更多的控制權,則可以將其存儲在一個數組中,您可以在其中安全地依賴元素的順序,從而依賴鍵:Object.entries()datamenuIndexesmenuIndexes
const pathToParse = { buildings: [ { name: 'office', building_styles: [ { name: 'interior', rooms: [ { name: 'open space', filling_types: [ { name: 'furniture', inventories: [{ id: 1, name: 'tv' }, { id: 2, name: 'chair' }, { id: 3, name: 'table' }, ] } ] } ] }, ] }, ] };
const menuIndexes = [{key: 'buildings', index: 0}, {key: 'building_styles', index: 0}, {key: 'rooms', index: 0}, {key: 'filling_types', index: 0}, {key: 'inventories', index: 0}, ];
function getPath(data, [{key, index}={}, ...rest]) {
if(!key)
return [];
const obj = data[key][index];
return [obj.name, ...getPath(obj, rest)];
}
console.log(getPath(pathToParse, menuIndexes));

TA貢獻1780條經驗 獲得超1個贊
像往常一樣,我會在一些可重用的部件上構建這樣的函數。這是我的方法:
// Utility functions
const path = (obj, names) =>
names .reduce ((o, n) => (o || {}) [n], obj)
const scan = (fn, init, xs) =>
xs .reduce (
(a, x, _, __, n = fn (a .slice (-1) [0], x)) => [...a, n],
[init]
) .slice (1)
const pluck = (name) => (xs) =>
xs .map (x => x [name])
// Main function
const getBreadCrumbs = (data, indices) =>
pluck ('name') (scan (path, data, Object .entries (indices)))
// Sample data
const data = {buildings: [{name: "office", building_styles: [{building_style: 0}, {building_style: 1}, {building_style: 2}, {name: "interior", rooms: [{room: 0}, {room: 1}, {name: "open space", filling_types: [{filling_type: 0}, {name: "furniture", room_fillings: [{name: "items", inventories: [{id: 1, name: "tv"}, {id: 2, name: "chair"}, {id: 3, name: "table"}]}, {room_filling: 1}]}, {filling_type: 2}]}, {room: 3}]}, {building_style: 4}]}]}
const menuIndexes = {buildings: 0, building_styles: 3, rooms: 2, filling_types: 1, room_fillings: 0}
// Demo
console .log (getBreadCrumbs (data, menuIndexes))
我們這里有三個可重用的函數:
path
采用一個對象和節點名稱(字符串或整數)列表,并在給定路徑處返回值,或者如果缺少任何節點,則返回值。1 例如:undefined
path ({a: {b: [{c: 10}, {c: 20}, {c: 30}, {c: 40}]}}, ['a', 'b', 2, 'c']) //=> 30.
scan
與 非常相似,不同之處在于它不返回最終值,而是返回在每個步驟中計算的值的列表。例如,如果 是 ,則:Array.prototype.reduce
add
(x, y) => x + y
scan (add, 0, [1, 2, 3, 4, 5]) //=> [1, 3, 6, 10, 15]
拔出
將命名屬性從每個對象列表中拉出:pluck ('b') ([{a: 1, b: 2, c: 3}, {a: 10, b: 20, c: 30}, {a: 100, b: 200, c: 300}]) //=> [2, 20, 200]
在實踐中,我實際上會進一步考慮這些幫助器,根據 定義來定義,并在定義中使用和。但這對這個問題并不重要。path
const prop = (obj, name) => (obj || {}) [name]
const last = xs => xs.slice (-1) [0]
const tail = (xs) => xs .slice (-1)
scan
然后,我們的 main 函數可以簡單地使用這些條目以及 2,首先從索引中獲取條目,將該條目、我們的函數和數據傳遞給相關對象節點的列表,然后將結果與我們要提取的字符串一起傳遞給。Object.entries
path
scan
pluck
'name'
我幾乎每天都使用。 不太常見,但它足夠重要,它被包含在我通常的實用程序庫中。有了這樣的功能,編寫類似 的東西就非常簡單了。path
pluck
scan
getBreadCrumbs
1 旁注,我通常將其定義為,我發現這是最常用的。此表單恰好更適合所使用的代碼,但是將代碼調整為我的首選形式很容易:而不是 ,我們可以只編寫(names) => (obj) => ...
scan (path, data, ...)
scan ((a, ns) => path (ns) (a), data, ...)
2 正如尼克·帕森斯(Nick Parsons)的回答和感謝的評論所指出的那樣,將此信息存儲在一個顯式排序的數組中是有一個很好的論據,而不是依賴于一般對象獲得的奇怪和任意的順序。如果這樣做,則此代碼只能通過刪除 main 函數中的調用來更改。Object .entries

TA貢獻1840條經驗 獲得超5個贊
您可以像這樣定義一個遞歸函數,它循環訪問鍵并在數據中找到相應的對象。找到數據后,它會將名稱推送到輸出數組中,并使用此對象再次調用該函數,并且menuIndexesmenuIndexes
const displayBreadCrumbs = (data, menuIndexes) => {
const output = [];
Object.keys(menuIndexes).forEach(key => {
if (data[key] && Array.isArray(data[key]) && data[key][menuIndexes[key]]) {
output.push(data[key][menuIndexes[key]].name);
output.push(...displayBreadCrumbs(data[key][menuIndexes[key]], menuIndexes));
}
});
return output;
};
const data = { buildings: [ { name: 'office', building_styles: [ { name: 'interior', rooms: [ { name: 'open space', filling_types: [ { name: 'furniture', inventories: [{ id: 1, name: 'tv' }, { id: 2, name: 'chair' }, { id: 3, name: 'table' }, ] } ] } ] }, ] }, ] };
const menuIndexes = {
buildings: 0,
building_styles: 0,
rooms: 0,
room_fillings: 0,
filling_types: 0,
};
displayBreadCrumbs(data, menuIndexes); // ["office", "interior", "open space", "furniture"]
添加回答
舉報