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

如何让自定义类在Pug中支持each语法直接迭代

问题原因

Pug 的 each 迭代器不依赖ES6的Symbol.iterator迭代协议,也不会调用自定义的forEach方法,它的内部遍历逻辑是固定的:

  1. 先判断迭代目标是否包含length属性,如果有就按类数组处理,遍历索引0到length-1,直接通过目标[索引]的方式取对应元素
  2. 如果没有length属性,就按普通对象处理,遍历所有可枚举的键名,取对应键值

你的自定义类只有items、Symbol.iterator、forEach三个可访问成员,没有length属性,也不支持索引访问,所以Pug会把它当成普通对象遍历键名,自然不会得到你想要的结果。


解决方案

只要给你的自定义类实现类数组接口即可,不需要修改原有逻辑,有两种常用实现方式:

方案1:手动实现类数组属性和访问器

在原有类基础上添加length getter,同时实现索引访问代理:

class MyPaginator<T>{
  items: T[]

  // 新增:length getter,返回items的长度
  get length() {
    return this.items.length
  }

  // 新增:TS索引签名定义,可选
  [index: number]: T

  constructor(items: T[]) {
    this.items = items
    // 如果items初始化后不会动态变化,可以直接把元素挂载到实例索引上
    items.forEach((item, index) => {
      this[index] = item
    })

    // 如果items会动态更新,用Proxy做动态代理更合适,替换上面的循环即可
    // return new Proxy(this, {
    //   get(target, prop) {
    //     if (typeof prop === 'string' && /^\d+$/.test(prop)) {
    //       return target.items[Number(prop)]
    //     }
    //     return Reflect.get(target, prop)
    //   }
    // })
  }

  [Symbol.iterator](){
    return this.items[Symbol.iterator]();
  };

  forEach(callback: (item: T, index: number) => void): void {
    return this.items.forEach(callback);
  }
}

方案2:直接继承Array类(更简单)

如果你的分页器没有和Array原型冲突的自定义逻辑,直接继承Array是成本最低的方案,天生自带类数组的所有特性,原有迭代逻辑也可以正常保留:

class MyPaginator<T> extends Array<T>{
  // 可自定义分页相关扩展属性
  pageNum: number
  pageSize: number
  total: number

  constructor(pageNum: number, pageSize: number, total: number, items: T[]) {
    // 把分页数据传给父类Array构造函数
    super(...items)
    this.pageNum = pageNum
    this.pageSize = pageSize
    this.total = total
  }

  // 其他自定义方法不需要修改
}

两种方案实现后,你就可以直接在Pug中用each element in paginator直接迭代实例,不需要加.items后缀。

内容的提问来源于stack exchange,提问作者Levy Barbosa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 04:36:04