
本文介绍如何修正 javascript 中基于 getter 的分类树结构,使其既能保持面向对象特性,又支持 react 等框架中递归/层级渲染,并正确暴露父级名称与子项关系。
本文介绍如何修正 javascript 中基于 getter 的分类树结构,使其既能保持面向对象特性,又支持 react 等框架中递归/层级渲染,并正确暴露父级名称与子项关系。
在构建前端分类树(如商品类目导航)时,仅靠嵌套 getter 返回普通对象会导致类型丢失、无法访问父级信息、且难以统一遍历——正如原始代码中 categories.pets 创建了 Category 实例却未返回它,而是返回了一个无原型、无 title 属性的裸对象字面量,导致 <li>{category.title}</li> 渲染失败。
✅ 正确设计:让每个节点都是真正的 Category 实例
核心原则是:所有可被访问的分类节点(包括中间节点如 pets、cloth)都必须是 Category 类的实例,并通过 Object.defineProperty 动态添加可枚举的子节点 getter,而非返回新对象:
class Category {
constructor(readonly title: string) {} // 可直接使用 public readonly,更简洁
}
const categories = {
get pets() {
const pets = new Category('Pets');
Object.defineProperty(pets, 'dishes', {
get() {
return new Category('Dishes');
},
enumerable: true, // 关键:确保 Object.entries() 能遍历到
configurable: true,
});
return pets;
},
get cloth() {
const cloth = new Category('Cloth');
Object.defineProperty(cloth, 'accessories', {
get() {
return new Category('Accessories');
},
enumerable: true,
configurable: true,
});
return cloth;
}
};
这样 categories.pets 是 Category 实例(拥有 title),其 dishes 属性也是 Category 实例,且 Object.keys(categories.pets) 或 Object.entries(categories.pets) 将返回 [['dishes', Category]] —— 完全符合预期。
? 前端渲染:安全遍历 + 避免私有字段干扰
在 React 中渲染树形结构时,需注意:
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
-
Object.entries(category)会包含_title(若用下划线命名)或title自身(若未设为私有),导致重复或无效渲染; - 推荐使用
#title私有字段(ES2022+)彻底隔离内部属性:
class Category {
#title: string;
constructor(title: string) {
this.#title = title;
}
get title() {
return this.#title;
}
}
此时 Object.entries(instance) 不会包含 #title,无需额外过滤。
若需兼容旧环境,可在渲染时显式排除非业务属性:
-
{Object.entries(categories).map(([slug, category]) => (
- {category.title}
- {subCategory.title} ))}
-
{Object.entries(category)
.filter(([key]) => !key.startsWith('_') && key !== 'title') // 过滤内部字段
.map(([subSlug, subCategory]) => (
⚠️ 注意事项与进阶建议
-
不可变性:当前模式每次访问
categories.pets.dishes都新建实例。如需缓存,可在 getter 内部用WeakMap或私有字段做懒初始化。 -
扩展性:考虑将树构建逻辑抽离为工厂函数,例如
createCategory('Pets', { dishes: createCategory('Dishes') }),提升可读性与测试性。 -
TypeScript 提示:为
categories添加明确接口,避免类型推导丢失:
interface CategoryTree {
readonly pets: Category & { readonly dishes: Category };
readonly cloth: Category & { readonly accessories: Category };
}
最终,这种设计既保持了面向对象的语义清晰性(每个节点可继承、扩展、携带方法),又满足前端树形渲染对可枚举性、一致性与父子可追溯性的要求。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










