JavaScript buildLayerTreeData 函数语法详解

前言

在日常的Vue项目开发中,我们经常需要处理复杂的数据结构转换。本文将以一个实际的 buildLayerTreeData 函数为例,详细解析其中涉及的各种JavaScript/ES6+语法特性,帮助开发者更好地理解和应用这些概念。

完整函数代码

async function buildLayerTreeData() {
    const LegendData = [];
    const layerData = [];

    topicLegends.value.forEach((item) => {
      item.children = item.children.filter((ele) => ele.isManager && ele.layers.length);
      if (item.children.length > 0) {
        LegendData.push(item);
      }
    });

    Object.values(layerMap[sceneName.value]).forEach((layer) => {
      LegendData.forEach((legend) => {
        if (legend.children.some((item) => item.layers.includes(layer.id))) {
          layerData.push(layer);
        }
      });
    });

    const newLayerData = [];
    for (const layer of layerData) {
      let rawData = [];

      if (layer.layerConfig.layerType === 'landmarkLayer') {
        rawData = await gisDataManager.getLandmarkLayerData(layer);

        if (rawData.length > 0) {
          let landmarkLayerRawData = rawData.map((item) => {
            return {
              ...item,
              idLayer: layer.id,
              layerType: layer.layerConfig.layerType
            };
          });
          console.log(landmarkLayerRawData);
          newLayerData.push({
            layerName: layer.layerConfig.scatterType,
            icon: '',
            children: landmarkLayerRawData
          });
        }
      } else if (layer.layerConfig.layerType === 'trailLayer') {
        rawData = await gisDataManager.getTrailLayerData(layer);
        if (rawData.length > 0) {
          const trailMap = new Map();

          rawData.forEach((trailDataItem) => {
            const { name } = trailDataItem;
            if (!trailMap.has(name)) {
              trailMap.set(name, {
                ...trailDataItem,
                idLayer: layer.id,
                layerType: layer.layerConfig.layerType,
                id: name
              });
            }
          });

          const trailLayerRawData = [...trailMap.values()];
          newLayerData.push({
            layerName: layer.layerConfig.scatterType,
            icon: '',
            children: trailLayerRawData
          });
        }
      }
    }
    const newLayerTreeData = LegendData.map((group) => {
      return {
        legendGroupName: group.txt,
        legendGroup: group.children.map((child) => {
          const matchedLayer = newLayerData.find((layer) => layer.layerName === child.txt);
          return {
            layerName: child.txt,
            icon: child.icon,
            children: matchedLayer ? matchedLayer.children : []
          };
        })
      };
    });

    layerTreeData.value = newLayerTreeData;
  }

语法详解

1. Array.prototype.forEach()

topicLegends.value.forEach((item) => { ... })

作用:遍历数组中的每个元素并执行回调函数。

特点

  • 不返回新数组,仅用于执行副作用操作
  • 常用于需要对每个数组元素执行相同操作的场景
  • 回调函数接收三个参数:(element, index, array)

2. Array.prototype.map()

let landmarkLayerRawData = rawData.map((item) => {
  return {
    ...item,
    idLayer: layer.id,
    layerType: layer.layerConfig.layerType
  };
});

作用:创建一个新数组,新数组的元素是原数组元素经过回调函数处理后的值。

特点

  • 返回与原数组长度相同的新数组
  • 不会改变原数组
  • 常用于数据转换和格式化

3. Array.prototype.filter()

item.children = item.children.filter((ele) => ele.isManager && ele.layers.length)

作用:创建一个新数组,包含通过回调函数测试的所有元素。

特点

  • 返回符合条件的元素组成的新数组
  • 回调函数返回 truthy 值时保留该元素
  • 常用于数据筛选

4. Array.prototype.push()

LegendData.push(item);

作用:向数组末尾添加一个或多个元素。

返回值:数组的新长度。

5. Array.prototype.some()

if (legend.children.some((item) => item.layers.includes(layer.id))) {
  layerData.push(layer);
}

作用:测试数组中是否至少有一个元素通过回调函数的测试。

返回值:布尔值,true 表示至少有一个元素满足条件。

6. Array.prototype.find()

const matchedLayer = newLayerData.find((layer) => layer.layerName === child.txt);

作用:返回数组中满足回调函数测试的第一个元素。

返回值:找到的元素对象或 undefined

7. Array.prototype.includes()

item.layers.includes(layer.id)

作用:判断数组是否包含指定的值。

返回值:布尔值。

8. 扩展运算符 ...(数组应用)

const trailLayerRawData = [...trailMap.values()];

作用:将可迭代对象(如 Map.values()Set、字符串等)转换为数组。

优点:简洁明了,代码可读性强。

对象操作

9. Object.values()

Object.values(layerMap[sceneName.value])

作用:返回一个包含对象所有可枚举属性值的数组。

返回值:对象所有属性值组成的数组。

10. 对象扩展运算符 ...

return {
  ...item,
  idLayer: layer.id,
  layerType: layer.layerConfig.layerType
};

作用:将对象的所有可枚举属性复制到新对象中。

特点

  • 实现对象的浅拷贝
  • 可以同时添加或覆盖属性
  • 比使用 Object.assign() 更简洁

11. 对象字面量属性简写

{
  layerName: layer.layerConfig.scatterType,
  icon: '',
  children: landmarkLayerRawData
}

作用:创建对象的简洁语法。

简写规则:当属性名和变量名相同时,可以只写属性名。

Map 数据结构

12. Map 的创建和操作

const trailMap = new Map();
trailMap.set(name, { ...trailDataItem, idLayer: layer.id });
trailMap.has(name);
const trailLayerRawData = [...trailMap.values()];

Map 常用方法

  • new Map():创建新的 Map 实例
  • Map.set(key, value):设置键值对
  • Map.get(key):获取键对应的值
  • Map.has(key):检查是否存在指定键
  • Map.delete(key):删除指定键
  • Map.values():返回所有值的迭代器
  • Map.keys():返回所有键的迭代器
  • Map.entries():返回所有键值对的迭代器

优势:相比普通对象,Map 的键可以是任意类型,且有更好的性能表现。

异步处理

13. async/await

async function buildLayerTreeData() {
  rawData = await gisDataManager.getLandmarkLayerData(layer);
}

async 函数

  • 声明异步函数,返回 Promise 对象
  • 函数内部可以使用 await 关键字

await 关键字

  • 暂停函数执行,等待 Promise 解决
  • 只能在 async 函数内部使用
  • 简化了 Promise 的链式调用

Vue 3 响应式

14. ref() 响应式引用

const LegendData = [];
layerTreeData.value = newLayerTreeData;

特点

  • 使用 ref() 创建响应式引用
  • 通过 .value 访问或修改值
  • 在模板中使用时会自动解包

逻辑运算符

15. 短路求值

item.children.filter((ele) => ele.isManager && ele.layers.length)

&& (逻辑与)

  • 两个条件都为 true 时返回 true
  • 常用于组合多个判断条件
  • 具有短路特性:第一个条件为 false 时不会判断第二个

解构赋值

16. 对象解构

const { name } = trailDataItem;

作用:从对象中提取属性到变量。

优点

  • 代码更简洁
  • 避免重复编写对象名
  • 可以同时提取多个属性

扩展解构

const { name, age, address } = trailDataItem;
const { name: userName } = trailDataItem; // 重命名
const { name = '默认值' } = trailDataItem; // 设置默认值

总结

这个 buildLayerTreeData 函数充分展示了现代 JavaScript 的强大功能:

  1. 数组方法链式调用:通过 forEachfiltermap 等方法实现数据转换
  2. ES6+ 新特性:扩展运算符、解构赋值、Map 数据结构等提升开发效率
  3. 异步处理:async/await 简化异步流程控制
  4. 响应式编程:与 Vue 3 框架完美结合

掌握这些语法特性不仅能让代码更加简洁优雅,还能提高开发效率和代码质量。在实际项目中灵活运用这些特性,是成为优秀 JavaScript 开发者的必经之路。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐