Javascript 使用函数正确编写getter和setter

Javascript 使用函数正确编写getter和setter,javascript,Javascript,我试图用getter和setter编写一个简单的对象,我不完全确定代码是否正确,我对在实例中使用下划线也有点困惑。我当前遇到的错误是menu.addDishToCourses不是一个函数,而是控制台记录膳食,将其属性显示为一个函数。有什么好处 let menu = { _courses: { _appetizer: [], _main: [], _dessert: [], get appetizers() {

我试图用getter和setter编写一个简单的对象,我不完全确定代码是否正确,我对在实例中使用下划线也有点困惑。我当前遇到的错误是
menu.addDishToCourses不是一个函数
,而是控制台记录膳食,将其属性显示为一个函数。有什么好处

let menu = {
    _courses: {
        _appetizer: [],
        _main: [],
        _dessert: [],

        get appetizers() {
            return this._courses.appetizer;
        },
        set appetizers(appetizerInput) {
          this._courses.appetizer = appetizerIn;
        },

        get mains() {
            return this._courses.main;
        },
        set mains(mainsInput) {
          this._courses.main = mainsInput;
        },

        get desserts() {
            return this._courses.dessert;
        },

        set desserts(dessertsInput) {
            this._courses.deseserts = dessertInput;
        },
        get courses() {
            return {
                appetizers: this._courses.appetizer,
                mains: this._courses.main,
                desserts: this._courses.dessert,
            };
        },

        addDishToCourses(courseName, dishName, dishPrice) {
            const dish = {
                name: dishName,
                price: dishPrice,
            };
            this._courses[courseName].push(dish);
        },

        getRandomDishFromCourse(courseName) {
            const dishes = this._courses[courseName];
            const RandomIndex = Math.floor(Math.random() * dishes.length);
            return dishes[RandomIndex];
        },
        generateRandomMeal() {
            let appetizer = this.getRandomDishFromCourse('appetizer');
            let main = this.getRandomDishFromCourse('main');
            let dessert = this.getRandomDishFromCourse('dessert');
            let totalPrice = appetizer.price + main.price + dessert.price;

            return `You order and appetizer ${appetizer.name},${main.name} and a main dish ${main.price} and a dessert ${dessert.price}. Total price was $${totalProice}. `;
        },
    }
};
menu.addDishToCourses('_appetizer', 'pepperoni', 5.43);
menu.addDishToCourses('_mains', 'steak', 18.0);
menu.addDishToCourses('_dessert', 'pie', 3.5);

你有一个范围问题
在getter和setter方法中是指
菜单
属性,而不是
菜单
对象本身

您可能希望设计类似以下内容的
菜单
对象:

let菜单={
_课程:{
_开胃菜:[],
_main:[],
_甜点:[],
吃开胃菜{
把这个还给我
},
获取main(){
把这个还给我
},
吃甜点{
把这个还给我
}
},
获取课程(){
返回{
开胃菜:这个,
梅因:这个,
甜点:这个,
};
},
添加DishToCourses(课程名称、dishName、dishPrice){
让盘子={
姓名:dishName,,
价格:价格,,
};
//console.log(this._课程[courseName]);
这个._课程[课程名称].推(碟);
}
};
菜单。添加菜肴(“开胃菜”、“辣香肠”,5.43);
菜单。添加菜肴(“主菜”、“牛排”,18.0);
菜单。添加餐前菜(“甜点”、“馅饼”3.5);

控制台.日志(菜单.课程)
设置
菜单的方式有一个属性:
\u课程
menu.adddishcourses()
不是函数,而是
menu.\u courses.adddishcourses()
是函数

我认为您应该退一步,问问为什么要使用getter和setter,而不仅仅是访问属性和函数。如果需要一个getter或setter,这应该是显而易见的。如果这变得更大,它将很难维持

话虽如此,如果要继续当前方案,只需将要从
菜单
调用的函数置于
菜单

let菜单={
添加DishToCourses(课程名称、dishName、dishPrice){
常数盘={
姓名:dishName,,
价格:价格,,
};
这个._课程[课程名称].推(碟);
},
买开胃菜{
把这个还给我。_课程。_开胃菜;
},
_课程:{
_开胃菜:[],
_main:[],
_甜点:[],
}
}
菜单。添加菜肴(“开胃菜”、“辣香肠”,5.43);
console.log(菜单.开胃菜)
几个要点(其中一些已在各种评论中提到):

  • 下划线是根据惯例规定的隐私,不做任何实际强制隐私的事情。该状态对于菜单用户仍然是可直接访问的

  • 在我看来,使用具有公共可访问属性的getter/setter是徒劳的。getter/setter的目的是在访问state时强制执行约定,以便以后可以更改内部实现细节,而不会影响模块的用户。如果他们可以直接访问并改变您的状态,那么getter/setter就是杂乱无章的,因为您无法知道模块用户是否遵守了您隐含的隐私约定

  • 有几种方法可以用JavaScript将您的状态设置为私有(请参见下面的一个选项)。然而,如果真正的私有状态并不重要,那么为了清晰起见,只需删除getter/setter和下划线即可。只需创建一个普通对象,其中包含一些额外的函数,这些函数为操纵该状态添加了真正有用的行为

  • 现在,如果你真的想让你的菜单保持私有状态,并控制对它的访问,这里有一个例子可以说明如何做到这一点。对我来说,这种方法更干净、更容易阅读,并且实际上实现了您的预期

    const menu=(函数菜单(){
    //此状态是私有范围
    常数课程={
    开胃菜:[],
    main:[],
    甜点:[]
    };
    //这些函数是私有范围的,除非公开(见下文)
    函数addDish(课程、名称、价格){
    课程[课程]。推送({name,price});
    }
    函数getDishesByCourse(课程){
    返回课程[课程];
    }
    //这就是你向外界透露的
    返回{addDish,getDishesByCourse};
    })();
    菜单。添加菜肴(“开胃菜”、“辣香肠”,5.43);
    
    console.log(menu.getDishesByCourse(“开胃菜”)JavaScript根本不是我的强项,但下划线用于getter/setter映射到的内部属性。尚未深入研究,但addDishToCourses似乎有“作为家长的课程而不是菜单”
    menu
    有一个属性,
    \U courses
    。其他所有内容都被定义为其中的一员,因此您需要编写
    菜单。\课程..
    。此外,下划线是一种惯例,有些人用它来表示私有的东西。不要求使用本公约。最后,要定义一个方法,实际上需要创建一个属性并为其分配一个函数,如:
    addDishToCourses:function(courseName,dishName,dishPrice){…}
    。呸,你比我快了几秒钟,哈哈。应该注意的是,下划线只表示私有字段/方法,在这种情况下,它们不是真正需要的?谢谢,先生。下划线把我弄糊涂了,我现在明白了。