JS使用setter返回undefined,getter触发TypeError问题求助
解决JavaScript Getter/Setter实现今日菜单的问题
问题描述
尝试用JavaScript的getter和setter实现简易「今日菜单」程序,需求是从对象数组中随机获取食物名称和对应价格。但遇到以下问题:
- 调用
menu.priceToCheck与menu.mealToCheck时返回undefined - 调用getter
todaysSpecial时触发错误:TypeError: Cannot convert undefined or null to object - 预期输出示例:
The menu today has pizza for only 13 dollars - 不使用getter/setter的代码可正常运行
问题代码
let menu = { _meals : [ {"burger": 14}, {"mouzakas": 12}, {"pasta": 10}, {"pizza": 13}, ], set meal(mealToCheck) { if (typeof mealToCheck === 'string') { let random_index = Math.floor(Math.random() * this._meals.length); let new_obj = this._meals[random_index]; return new_obj = mealToCheck; } else { return 'input error'; } }, set price(priceToCheck) { if (typeof priceToCheck === 'number') { return Object.values(this.new_obj) = priceToCheck; } else { return 'input error'; } }, get todaysSpecial() { if (Object.keys(this.new_obj) !== '' && Object.values(this.new_obj) !== 0) { return 'The menu today has ' + Object.keys(this.new_obj) + ' for only ' + Object.values(this.new_obj) + ' dollars'; } else { return 'Meal or price was not set correctly!' } } }; console.log(menu.priceToCheck); console.log(menu.mealToCheck) ; console.log(menu.todaysSpecial);
补充:可正常运行的无Getter/Setter代码
meals = [ {"burger": 14}, {"mouzakas": 12}, {"pasta": 10}, {"pizza": 13}, ]; let random_index = Math.floor(Math.random() * meals.length); let obj = meals[random_index]; console.log(obj[0]); console.log('The menu today has ' + Object.keys(obj) + ' for only ' + Object.values(obj) + ' dollars'); console.log(Object.keys(obj)); console.log(Object.values(obj));
错误原因分析
- Setter使用逻辑错误:
- Setter的作用是给对象属性赋值,不是直接调用获取值,你定义的setter是
meal和price,但却调用了不存在的mealToCheck、priceToCheck属性,自然返回undefined。 - Setter不应该返回值,它的职责是修改对象状态,而不是返回结果。
- Setter的作用是给对象属性赋值,不是直接调用获取值,你定义的setter是
- 实例属性未正确存储:
- 你在setter里定义的
new_obj是局部变量,不是menu对象的实例属性,导致getter中this.new_obj为undefined,调用Object.keys()时触发类型错误。
- 你在setter里定义的
- Price setter冗余且逻辑错误:
- 价格是菜品对象的固有属性,不需要单独设置,随机选中菜品后就能直接获取价格,单独的price setter完全没必要,且代码中
Object.values(this.new_obj) = priceToCheck是非法赋值逻辑。
- 价格是菜品对象的固有属性,不需要单独设置,随机选中菜品后就能直接获取价格,单独的price setter完全没必要,且代码中
- Getter中的判断逻辑错误:
Object.keys(this.new_obj)返回的是数组,和空字符串''比较永远不成立;Object.values(this.new_obj)返回的也是数组,和0比较也不正确。
修复后的代码
let menu = { _meals: [ {"burger": 14}, {"mouzakas": 12}, {"pasta": 10}, {"pizza": 13}, ], _selectedMeal: null, // 存储选中的菜品对象 // 用setter触发随机选餐逻辑,参数可作为触发标识(比如传入任意字符串触发) set meal(trigger) { if (typeof trigger === 'string') { const randomIndex = Math.floor(Math.random() * this._meals.length); this._selectedMeal = this._meals[randomIndex]; } else { console.error('输入错误:请传入字符串触发随机选餐'); } }, get todaysSpecial() { if (!this._selectedMeal) { return '请先触发随机选餐!'; } const mealName = Object.keys(this._selectedMeal)[0]; const mealPrice = Object.values(this._selectedMeal)[0]; return `The menu today has ${mealName} for only ${mealPrice} dollars`; } }; // 正确调用setter:给meal属性赋值触发随机选餐 menu.meal = 'random'; console.log(menu.todaysSpecial);
修复说明
- 新增实例属性存储选中菜品:添加
_selectedMeal来保存随机选中的菜品对象,确保getter能访问到有效数据。 - 修正Setter逻辑:
- Setter仅负责触发随机选餐并存储结果,不再错误返回值。
- 通过给
menu.meal赋值(传入任意字符串)来触发选餐逻辑,符合setter的使用规范。
- 移除冗余的Price Setter:价格从选中的菜品对象中直接提取,不需要单独设置。
- 优化Getter判断与取值:
- 先判断是否已选中菜品,避免
undefined错误。 - 直接提取数组第一个元素(因为每个菜品对象只有一个键值对),让结果更清晰。
- 先判断是否已选中菜品,避免
- 修正调用方式:不再调用不存在的
mealToCheck/priceToCheck,而是通过给menu.meal赋值触发逻辑,再调用menu.todaysSpecial获取结果。
内容的提问来源于stack exchange,提问作者Gizmapps
相关产品推荐
相关产品推荐

