Javascript-форум (https://javascript.ru/forum/)
-   Prototype & script.aculo.us (https://javascript.ru/forum/prototype-script-aculo-us/)
-   -   Геттеры и сеттеры (https://javascript.ru/forum/prototype-script-aculo-us/80356-gettery-i-settery.html)

DVV 26.05.2020 20:49

Геттеры и сеттеры
 
Изучаю основы ООП, классы. Столкнулся с проблемой, ответ на который не могу нагуглить (возможно ищу не по тем ключам, так как тема для меня относительно новая). Написал объект с одним приватным свойством и методом для его получения, когда пользователь кликает по одной из двух кнопок выбора пола. Все работает.

let user = {
        _sex: '',
        setSex: function () {
            document.querySelectorAll('.sex-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    this._sex = btn.value;
                });
            });
        }
    };

    user.setSex();


Но при попытке создания геттера для класса по аналогии возникли трудности. Не понимаю, как можно сделать установку приватного свойства класса при переборе псевдомассива кнопок или любых других элементов.

class User {
        constructor(sex) {
            this._sex = sex;
        }

        set sex(sex) { // откуда будет браться параметр для сеттера не пойму
            document.querySelectorAll('.sex-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    user.sex = btn.value;
                });
            });
        }

        get sex() {
            return this._sex;
        }
    }

    let user = new User();
    user.sex // что сюда передавать тоже не пойму

рони 26.05.2020 21:18

DVV,
<input class="sex-btn" type="button" value="m">
<input class="sex-btn" type="button" value="w">
<script>
class User {
        constructor(sex) {
            this._sex = sex;
            document.querySelectorAll('.sex-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    console.log('before', this.sex)
                    this.sex = btn.value;
                    console.log('after', this.sex)
                });
            });
        }

        set sex(sex) {
            this._sex = sex;
        }

        get sex() {
            return this._sex;
        }
    }

    let user = new User('test');
    user.sex = 123// что сюда передавать тоже не пойму

  </script>

DVV 26.05.2020 22:24

Круто. Все работает. Спасибо огромное. Скажите, пожалуйста, то есть всегда в случае псевдомассива в классе надо геттеры и сеттеры в конструкторе писать?
И еще, а в User('test') что означает test? Просто в качестве временного свойства или его можно пустым оставлять?
И зачем тогда
set sex(sex) {
this._sex = sex;
}
Код и без него работает
С одной стороны все вроде понятно, а с другой - что-то я запутался

рони 26.05.2020 22:39

DVV,
придут люди которые в этом разбираются, может ответят на ваши вопросы более досконально.
Цитата:

Сообщение от DVV
а в User('test') что означает test?

это обозначает что пол равный test был у user при создании. уберите строку 26. и посмотрите консоль.
Цитата:

Сообщение от DVV
И зачем тогда
set sex(sex) {
this._sex = sex;
}
Код и без него работает

не сработает изменение кнопками
Цитата:

Сообщение от DVV
Скажите, пожалуйста, то есть всегда в случае псевдомассива в классе надо геттеры и сеттеры в конструкторе писать?

не осилил.

Malleys 26.05.2020 22:54

Цитата:

Сообщение от DVV
Написал объект с одним приватным свойством

Почему вы решили, что добавление знака «_» в начало имени свойства делает его приватным?

Его совершенно спокойно можно читать и изменять. К вашим примерам из первого сообщения...
user._sex = "와";
console.log(user._sex); // выводит "와"


Конструкции вида...
set sex(sex) {
     this._sex = sex;
}
 
get sex() {
      return this._sex;
}
могут быть заменены на
sex = "";
или
this.sex = "";
в конструкторе...

<input class="sex-btn" type="button" value="m">
<input class="sex-btn" type="button" value="w">
<script>
    class User {
        constructor(sex) {
            this.sex = sex;
            document.querySelectorAll('.sex-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    console.log('before', this.sex)
                    this.sex = btn.value;
                    console.log('after', this.sex)
                });
            });
        }
    }

    let user = new User('test');
    user.sex = 123;
</script>

Malleys 27.05.2020 00:44

То, как вы используете понятие приватность, не имеет особого смысла. Для лучшего контроля над свойством его делают приватным, а запись значения осуществляется через специальный метод, который называют, если записать при помощи IPA, [ˈsɛɾəɹ] (setter method) и чтение значения осуществляется через специальный метод, который называют [ˈkɛɾəɹ] или [ˈɡɛɾəɹ] (getter method).

При помощи приватного свойства...
<input class="sex-btn" type="button" value="m">
<input class="sex-btn" type="button" value="f">
<script>
    class User {
        #sex = null;

        constructor(sex) {
            this.sex = sex;

            document.querySelectorAll('.sex-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    console.log('before', this.sex)
                    this.sex = btn.value;
                    console.log('after', this.sex)
                });
            });
        }

        set sex(sex) {
            if(sex !== "m" && sex !== "f")
                throw new Error(`The provided value '${sex}' is not a valid enum value of type UserSex—use 'm' or 'f'.`);

            this.#sex = sex;
        }
 
        get sex() {
            return this.#sex;
        }
    }

    let user = new User('m'); // неправильные значения типа test будут вызывать исключение
    user.sex = 123;
</script>


При помощи ассоциативного массива... (подойдет для браузеров, где не поддерживаются приватные свойства)
<input class="sex-btn" type="button" value="m">
<input class="sex-btn" type="button" value="f">
<script>
    const User = (() => {

    const userSex = new WeakMap();

    return class User {
        constructor(sex) {
            this.sex = sex;

            document.querySelectorAll('.sex-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    console.log('before', this.sex)
                    this.sex = btn.value;
                    console.log('after', this.sex)
                });
            });
        }

        set sex(sex) {
            if(sex !== "m" && sex !== "f")
                throw new Error(`The provided value '${sex}' is not a valid enum value of type UserSex—use 'm' or 'f'.`);

            userSex.set(this, sex);
        }
 
        get sex() {
            return userSex.get(this);
        }
    }
    })();

    let user = new User('m');
    user.sex = 123;
</script>

Теперь в поле sex хранится всегда правильное значение — либо 'm', либо 'f'.

Поскольку класс User похож на модель, то скорей всего вам нужно вынести работу с DOM из его определения.

DVV 27.05.2020 12:50

Про геттеры и сеттеры я знаю, но гдя я только не читал про них. Везде даны простейшие примеры, которые зачастую с одного ресурса учебного копипастятся другими. Ничего подобного с псевдомассивами я нигде не нашел. Был бы очень благодарен, если подскажите ресурсы, где можно об этом подробно почитать.
А зачем нужна эта строка и именно знак #? #sex = null;
Кроме того, попробовал закомментировать геттер и сеттер в первом примере с 19 по 28 строку. Все работает и без них.

Rise 27.05.2020 13:39

Цитата:

Сообщение от DVV
подскажите ресурсы

В меню есть ссылка на Учебник, там есть всё.

Malleys 27.05.2020 14:07

Цитата:

Сообщение от DVV
Кроме того, попробовал закомментировать геттер и сеттер в первом примере с 19 по 28 строку. Все работает и без них.

Когда удалили, то изчесли приватность и проверки.

Цитата:

Сообщение от DVV
А зачем нужна эта строка и именно знак #? #sex = null;

Например для того, чтобы хранить значение, которое устанавливается через setter. Свойство, которое начинается на # является реально приватным, т. е. его невозможно прочитать вне определения класса.

DVV 27.05.2020 16:20

Понял. Буду разбираться дальше в ООП. Спасибо)))


Часовой пояс GMT +3, время: 20:47.