遍历带过滤结果的对象嵌套结构及API数据有序展示问题求助
嘿,我看你现在遇到的问题是调用API拿到和波兰接壤的国家数据后,转成对象没法按想要的顺序展示对吧?核心问题其实出在普通JS对象并不适合用来维护自定义顺序的集合——虽然ES6之后对象键有插入顺序的规则,但如果要实现比如按名称、人口这类自定义排序,转成对象反而会给顺序控制添乱。
我来一步步给你拆解解决方案:
1. 为啥你的代码会搞乱顺序?
你现在用toObject把过滤后的数组转成了以国家名称大写为键的对象,之后用Object.entries转成键值对数组。但Object.entries的顺序是跟着对象键的顺序走的,这个顺序没法轻易自定义。如果你的核心需求是按特定顺序展示数据,那转对象这一步其实完全没必要,反而破坏了数组原本能轻松控制顺序的优势。
2. 推荐方案:保留数组,先排序再展示
如果只是要按指定顺序展示过滤后的国家,直接在过滤之后给数组排序就行,完全不用转对象。比如假设你想按国家英文名称升序排列:
// 定义排序规则:按国家名称升序 const sortCountriesByName = (a, b) => a.name.localeCompare(b.name); fetch('https://restcountries.eu/rest/v2/') .then(resp => resp.json()) .then(data => data.filter(country => country.borders.includes('POL'))) .then(filteredCountries => filteredCountries.sort(sortCountriesByName)) // 先排序 .then(sortedCountries => { // 这里遍历排序后的数组,按需展示就行 sortedCountries.forEach(country => { console.log(`${country.name} | 首都:${country.capital}`); // 要是往页面上插元素,直接在这里操作DOM就行 }); }) .catch(err => console.error('请求出问题啦:', err));
如果确实需要对象来做快速查找(比如后续要通过国家名称快速取数据),那可以同时保留排序后的数组和对象:
const toCountryObject = (array) => array.reduce((obj, country) => { obj[country.name.toUpperCase()] = country; return obj; }, {}); const sortCountriesByName = (a, b) => a.name.localeCompare(b.name); fetch('https://restcountries.eu/rest/v2/') .then(resp => resp.json()) .then(data => data.filter(country => country.borders.includes('POL'))) .then(filteredCountries => { const sortedCountries = filteredCountries.sort(sortCountriesByName); const countryLookup = toCountryObject(sortedCountries); return { sortedCountries, countryLookup }; }) .then(({ sortedCountries, countryLookup }) => { // 用sortedCountries按顺序展示 sortedCountries.forEach(country => console.log(country.name)); // 用countryLookup快速查找 console.log('德国的数据:', countryLookup['GERMANY']); }) .catch(err => console.error('请求出错:', err));
3. 要是非得用对象,怎么保证顺序?
如果因为某些原因必须用对象存储,那你得先维护一个排序后的键数组,然后通过这个数组来遍历对象,这样就能保证顺序了:
const toCountryObject = (array) => array.reduce((obj, country) => { obj[country.name.toUpperCase()] = country; return obj; }, {}); fetch('https://restcountries.eu/rest/v2/') .then(resp => resp.json()) .then(data => data.filter(country => country.borders.includes('POL'))) .then(filteredCountries => { const countryObj = toCountryObject(filteredCountries); // 先把键按想要的顺序排好,比如按名称升序 const sortedKeys = Object.keys(countryObj).sort((a, b) => a.localeCompare(b)); return { countryObj, sortedKeys }; }) .then(({ countryObj, sortedKeys }) => { // 用排序后的键数组遍历对象,就能保证顺序啦 sortedKeys.forEach(key => { console.log(`${key}:首都${countryObj[key].capital}`); }); }) .catch(err => console.error('请求出错:', err));
4. 顺便提下你原代码的小问题
你最后一行代码Object.entries(data).map(([key, value]) => ({ [key]: value })...有语法错误,应该是没写完。如果是想把键值对转回单个键的对象数组,正确写法是:
Object.entries(data).map(([key, value]) => ({ [key]: value }))
不过这步其实没啥必要,生成一堆单个键的对象反而不利于遍历展示。
总的来说,要控制顺序就优先用数组并提前排序,对象更适合做快速查找,不是用来做有序展示的~
内容的提问来源于stack exchange,提问作者Thomas

