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

JS类继承报错:Cannot read properties of undefined (reading 'push')

报错原因

报错触发的完整链路和代码问题如下:

  • 核心触发点是names访问器的递归调用+内部属性未初始化:当构造函数执行this.names = new Array(name)时,会自动调用你定义的set names方法;该方法内部写了this.names.push(newName),这里访问this.names会优先触发names的getter,而此时你从来没有给内部存储属性this._names赋过初始值,getter返回的是undefined,对undefined调用push方法就直接抛出你看到的TypeError。
  • names的setter逻辑不符合需求:setter的作用是响应属性赋值操作,你要实现的是“名称更新时追加到历史名称数组”,完全不需要给names写setter,更不能在setter里访问属性自身造成递归。
  • 数组初始化写法存在隐式bug:new Array(name)当传入单个字符串参数时,会创建一个长度等于字符串长度的空槽数组,而不是把name作为首个元素的数组。比如new Array("Joe")得到的是长度为3的空数组,不是["Joe"]。
  • 实例化Child时未传参,会导致构造函数里的name为undefined,进一步干扰初始化逻辑。
修正后的代码
class Child {
  constructor(name) {
    // 先初始化内部存储的历史名称数组,避免访问未定义属性
    this._names = [];
    // 赋值名称,会触发name的setter,自动把初始名称加入历史数组
    this.name = name;
  }

  get name() {
    return this._name;
  }

  get names() {
    // 返回数组浅拷贝,避免外部直接修改内部存储的数组
    return [...this._names];
  }

  set name(newName) {
    this._name = newName;
    // 新名称追加到历史数组
    this._names.push(newName);
  }
}

class Girl extends Child {
  constructor(name = "Sally") {
    super(name);
  }
}

class Boy extends Child {
  constructor(name = "Joe") {
    super(name);
  }
}

// 测试代码
const girl = new Girl();
console.log(girl.name); // 输出:Sally
console.log(girl.names); // 输出:["Sally"]
girl.name = "Alice";
console.log(girl.name); // 输出:Alice
console.log(girl.names); // 输出:["Sally", "Alice"]
关键修正说明
  • 把内部存储的_names数组初始化放在构造函数最开头,从根源避免访问未定义属性的问题
  • 移除了错误的names setter:历史名称数组由内部逻辑维护,不需要外部直接赋值,仅暴露getter给外部读取即可,避免外部破坏数组结构
  • 把追加名称到历史的逻辑放到name的setter中:只要名称被修改(包括构造函数里的初始赋值),就自动把新名称加入历史数组,完全匹配“存储所有使用过的名称”的需求
  • 修正数组初始化逻辑:直接用数组字面量[]创建空数组,再通过push添加元素,避开new Array()传入单个参数的隐式坑
  • 读取names时返回数组的浅拷贝,防止外部拿到内部数组引用后随意修改,破坏实例内部状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:09:33