如何正确编写含函数的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
相关产品推荐
相关产品推荐

