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

如何正确编写含函数的Getters和Setters?menu.addDishToCourses报错求解

嘿,我来帮你拆解一下遇到的这几个问题~

问题分析与解决

1. 为什么会报错menu.addDishToCourses is not a function?

首先你提到控制台打印meal时这个属性是函数,但调用的却是menu.addDishToCourses——这里大概率是笔误,或者你把方法定义在了meal对象里而非menu里。另外看你给出的代码片段,还有几个明显的小错误会间接导致这类异常:

  • set appetizers里的拼写错误:this._cou...应该是this._courses,这个错误会让setter无法正常工作,甚至抛出异常中断代码执行;
  • 属性名前后不一致:你内部定义的是_appetizer(单数),但getter叫appetizers(复数),容易导致访问路径出错。

我给你补全并修正了正确的代码结构,你可以对比参考:

let menu = {
  _courses: {
    _appetizers: [], // 统一用复数更符合语义
    _mains: [],
    _desserts: []
  },
  // appetizers的getter:对外暴露的访问入口
  get appetizers() {
    return this._courses._appetizers;
  },
  // appetizers的setter:可以在这里做数据校验
  set appetizers(appetizerInput) {
    if (Array.isArray(appetizerInput)) {
      this._courses._appetizers = appetizerInput;
    } else {
      console.error('开胃菜必须传入数组格式!');
    }
  },
  // 补全主菜和甜点的getter/setter
  get mains() {
    return this._courses._mains;
  },
  set mains(mainInput) {
    if (Array.isArray(mainInput)) {
      this._courses._mains = mainInput;
    } else {
      console.error('主菜必须传入数组格式!');
    }
  },
  get desserts() {
    return this._courses._desserts;
  },
  set desserts(dessertInput) {
    if (Array.isArray(dessertInput)) {
      this._courses._desserts = dessertInput;
    } else {
      console.error('甜点必须传入数组格式!');
    }
  },
  // 关键:addDishToCourses必须定义在menu对象内部
  addDishToCourses(courseType, dishName, dishPrice) {
    const dish = { name: dishName, price: dishPrice };
    // 利用getter获取对应菜品数组,避免直接操作内部私有属性
    this[courseType].push(dish);
  },
  // 额外加个生成随机餐品的示例方法
  generateRandomMeal() {
    const pickRandom = arr => arr[Math.floor(Math.random() * arr.length)];
    const appetizer = pickRandom(this.appetizers);
    const main = pickRandom(this.mains);
    const dessert = pickRandom(this.desserts);
    return `今日随机餐:${appetizer.name} + ${main.name} + ${dessert.name},总价:${appetizer.price + main.price + dessert.price}元`;
  }
};

// 测试调用
menu.addDishToCourses('appetizers', '凯撒沙拉', 38);
menu.addDishToCourses('mains', '西冷牛排', 128);
menu.addDishToCourses('desserts', '提拉米苏', 42);

console.log(menu.generateRandomMeal());

2. 关于下划线_的使用场景

在JavaScript里,下划线开头的属性/方法是行业约定的“私有标识”——注意JS本身直到ES6才支持真正的私有字段(用#定义),下划线只是一种“语法糖”式的约定:告诉其他开发者「这个属性是内部逻辑用的,不要直接修改它,尽量通过getter/setter来访问和修改」。

比如你的_courses、_appetizers就是用来存储实际数据的内部属性,对外暴露的不带下划线的appetizers则是安全的访问入口,你可以在setter里做数据校验(比如确保输入是数组),避免外部乱改内部数据导致逻辑崩溃。

3. 额外需要注意的细节

  • 尽量保持属性名语义一致:单数/复数统一,避免自己写代码时混淆;
  • 方法必须作为对象的属性存在:如果把addDishToCourses定义在menu对象外面,或者写错了位置,就会出现“不是函数”的报错;
  • getter/setter的作用:除了封装内部数据,还能在获取/设置数据时做额外逻辑(比如格式转换、校验),不要只是单纯返回/赋值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:25:50