You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为JSON对象编写外观模式的最佳实践及代码重构咨询

问题描述

我正在处理一个JSON文件,主要针对其中的data属性进行数据转换。希望无需每次深入JSON结构,就能便捷地对restaurantName和joined执行.filter等操作。

示例JSON结构:

const data = [
  {
    position: 1,
    title: "Queues Near You",
    data: [
      [
        {
          restaurantName: "Tonkotsu",
          joined: false,
        },
        {
          restaurantName: "BurgerVille",
          joined: false,
        },
      ],
    ],
  },
  {
    position: 2,
    title: "Restaurants Near You",
    data: [
      [
        {
          restaurantName: "Seoreni",
          joined: false,
        },
        {
          restaurantName: "Jinmu",
          joined: false,
        },
      ],
    ],
  },
];

我编写了外观函数toRestaurantArray,它提取restaurantName并返回二维数组(如[["Tonkotsu","BurgerVille"], ["Seoreni", "Jinmu"]])以简化操作,同时编写了fromRestaurantArray用于从新数组还原JSON结构。

请问:

  1. 使用to和from函数的思路是否正确?若不正确,更好的方案是什么?
  2. 若思路正确,该如何重构下方代码的逻辑(忽略any类型)?我知道fromRestaurant中重复循环JSON结构的代码很差,但不知道优化方法。

当前TypeScript代码:

type RestaurantDetails = {
  restaurantName: string;
  joined: boolean;
};
 
type Restaurant = {
  position: number;
  title: string;
  data: Array<Array<RestaurantDetails>>;
};
 
function* zip(arrayOne: any[], arrayTwo: any[]) {
  const len = arrayOne.length;
  for (let i = 0; i < len; i++) {
    yield [arrayOne[i], arrayTwo[i]];
  }
}
 
// Expected output is to return just the list inside data
const toRestaurantsArray = (initialRestaurantsData: Restaurant[]) => {
  const allRestaurantNames: any = [];
  for (const eachRestaurantData of initialRestaurantsData) {
    const [restaurants] = eachRestaurantData.data;
    const restaurantNames = restaurants.map(
      ({ restaurantName }) => restaurantName
    );
    allRestaurantNames.push(restaurantNames);
  }
  return allRestaurantNames;
};
 
const fromRestaurantsArray = (
  restaurantsArray: any[],
  initialRestaurantsData: any[]
) => {
  const reconstructedRestaurantsData: any = [];
  for (const [restaurantNestedArray, eachRestaurantData] of zip(
    restaurantsArray,
    initialRestaurantsData
  )) {
    const dataProperty: any = [];
    for (const [restaurantName, eachRestaurantsInnerData] of zip(
      restaurantNestedArray,
      eachRestaurantData.data[0]
    )) {
      dataProperty.push({
        ...eachRestaurantsInnerData,
        restaurantName: restaurantName,
      });
    }
    const myTotal = { ...eachRestaurantData, data: dataProperty };
    reconstructedRestaurantsData.push(myTotal);
  }
  return reconstructedRestaurantsData;
};
 
const restoArray = toRestaurantsArray(data);
const filteredArray = restoArray.filter((arr:string[]) => arr.includes("Tonkotsu"))
const reconstructedArray = fromRestaurantsArray(filteredArray, data);
console.log(reconstructedArray)

解答

一、思路正确性判断

你用to和from函数做数据转换的思路是合理的,核心是把嵌套结构扁平化,降低操作复杂度。但当前实现有个明显局限:toRestaurantsArray只提取了restaurantName,如果之后要操作joined或其他字段,这个函数就无法复用。而且还原时过度依赖原始数据,一旦原始数据变动,还原结果可能出错。

如果你的需求仅针对restaurantName做过滤,当前思路没问题;但如果要支持多字段操作,更灵活的方案是提取完整的RestaurantDetails数组,而非只取名字。这样可以直接对数组里的对象执行filter、map等操作,还原时也不需要重复遍历原始嵌套结构,逻辑更清晰。

二、代码重构方案

1. 优化to函数:提取完整对象数组

把toRestaurantsArray改成提取每层的RestaurantDetails数组,直接支持全字段操作:

const toRestaurantsArray = (initialData: Restaurant[]): RestaurantDetails[][] => {
  return initialData.map(item => item.data[0]);
};

返回结构为[[{restaurantName: "...", joined: ...}, ...], [...]],可直接对每个子数组执行操作,比如过滤包含Tonkotsu的分组:

const restoArray = toRestaurantsArray(data);
const filteredArray = restoArray.filter(group => 
  group.some(resto => resto.restaurantName === "Tonkotsu")
);

2. 优化from函数:避免重复循环

重构后的from函数利用数组索引对应原始数据位置,直接替换data字段,彻底避免嵌套循环:

const fromRestaurantsArray = (transformedData: RestaurantDetails[][], initialData: Restaurant[]): Restaurant[] => {
  return transformedData.map((group, index) => ({
    ...initialData[index],
    data: [group] // 还原原始双层数组结构
  }));
};

3. 完整重构代码

type RestaurantDetails = {
  restaurantName: string;
  joined: boolean;
};
 
type Restaurant = {
  position: number;
  title: string;
  data: Array<Array<RestaurantDetails>>;
};
 
// 转换为可直接操作的对象数组
const toRestaurantsArray = (initialData: Restaurant[]): RestaurantDetails[][] => {
  return initialData.map(item => item.data[0]);
};
 
// 从转换后的数组还原原始结构
const fromRestaurantsArray = (transformedData: RestaurantDetails[][], initialData: Restaurant[]): Restaurant[] => {
  return transformedData.map((group, idx) => ({
    ...initialData[idx],
    data: [group]
  }));
};
 
// 使用示例
const restoArray = toRestaurantsArray(data);
// 过滤包含Tonkotsu的分组
const filteredArray = restoArray.filter(group => 
  group.some(r => r.restaurantName === "Tonkotsu")
);
// 还原结构
const reconstructedArray = fromRestaurantsArray(filteredArray, data);
console.log(reconstructedArray);

4. 进一步优化:支持自定义转换

如果需要针对不同字段做转换,可以给to函数添加映射参数,提升扩展性:

const toTransformedArray = <T>(
  initialData: Restaurant[],
  mapper: (item: RestaurantDetails) => T
): T[][] => {
  return initialData.map(item => item.data[0].map(mapper));
};

// 提取restaurantName
const nameArray = toTransformedArray(data, r => r.restaurantName);
// 提取joined状态
const joinedArray = toTransformedArray(data, r => r.joined);

内容的提问来源于stack exchange,提问作者meg hidey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 10:15:39