Свойства геттеры и сеттеры и немного инкапсуляции

геттеры и сеттеры

Есть два типа свойств у объекта:

  1. это свойства данные data properties - это все обычные свойства ключ: значение.
  2. это свойства аксессоры accessor properties - это уже функции которые во внешнем коде будут выглядеть как обычные свойства.

Синтаксис

// get and set
const user = {
    name: 'Dima',
    age:'24',

    get userAge () { // ключевое слово get (мы получаем значение)
        return this.age; // получаем наш возраст
    },

    set userAge(num){  // в пару к get идет set, он уже что то должен в себя принимать (мы устанавливаем значение)
        this.age = num;
    }
};

console.log(user.userAge); // при вызове мы не пишем userAge(). 
// геттер предпологает что внутри у нас уже есть какой то функционал и он нам позволяет работать с этим меотодом как с обычным совйством.
// Поэтому это называется свойство аксессор

console.log(user.userAge = 30);
console.log(user.userAge); // 30

Инкапсуляция

Опять немного ООП

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

function User(name, age) {
    this.name = name;
    this.age = age;

    this.say = function () {
        console.log(`Имя пользователя:${this.name}, возраст:${this.age}`);
    };
}

const ivan = new User('ivan', 30); // создадим новый экземпляр

console.log(ivan.name); // ivan
console.log(ivan.age); // 30
// все работает. Но так же мы можем и менять значения свойств объекта
ivan.name = 'dima';
ivan.age = 18;

ivan.say(); // dima, 18
// Для того и нужна инкапсуляция, что бы мы не могли так нагло вмешиваться в свойства.

Далее будем работать с этой же функцией. Если мы вместо свойства создадим переменную, это уже будут зачатки инкапсуляции. так как мы создали переменную, мы не можем поменять ее и даже получить. И что бы работать с такими переменными нам нужны гетер и сетер. Но немного не тот синтаксис о котором говорили ранее. Геттерами и сетарами так же называют любые методы которые позволяют получать либо устанавливать значения.

// например поменяем у нашей функции this.age на создание обычной переменной.

function User(name,age) {
    this.name = name;
    let userAge = age; 
    this.say = function() {
        console.log(`Имя пользователя:${this.name}, возраст:${userAge}`);
    };
}

const ivan = new User('ivan', 30); 
        

ivan.userAge = 50; // не можем поменять. Таким образом мы просто создали свойства userAge:50
ivan.say(); // age будет 30. Наша же переменная осталась нетронутая

Создаем свои get и set

А таким образом обходились до методов get и set:

function User(name, age) {
    this.name = name;
    let userAge = age;
    this.say = function () {
        console.log(`Имя пользователя:${this.name}, возраст:${userAge}`);
    };

    this.getAge = function () {   // создаем функцию которая возвращает нам age
        return userAge;
    };

    this.setAge = function (age) { // функция для установки значения

        if (typeof (age) === 'number' && age > 0 && age < 110) { // небольшое условие
            userAge = age; // если все хорошо устанавливаем.
        } else { // иначе ошибка
            console.log('недопустимое значение');
        }
    };
}

const ivan = new User('ivan', 40);
// теперь для получения возраста у нас есть определенная функция и для того что бы его поменять тоже
console.log(ivan.getAge()); // 40
ivan.setAge(30); // меняем возраст
ivan.setAge(300); // недопустимое значение.
console.log(ivan.getAge()); // 30


ivan.say();// Имя пользователя:ivan, возраст:30

Так вот мы и получили нашу инкапсуляцию. Теперь испробуем на классе.

Используем get и set в классе

В классах те свойства которые нам нужно скрыть мы добавляем нижнее подчеркивание. Это не синтаксис языка, это договоренность между программистами. Здесь мы уже будем использовать те самые методы геттер и сеттер которые изучили в начале, а то, что я писал выше как я и сказал это по сути старый вариант до get и set


class User{
    constructor(name,age) {
        this.name = name;
        this._age = age;  // пишем _age, что значит свойство приватное.Если другой программист это увидит, он будет значть, что это приват
    }

    say() {
        console.log(`Имя пользователя:${this.name}, возраст:${this._age}`);  
    }

    get age() {  // получаем приватное свойство
        return this._age; 
    }
    set age(age) { // метод для изменения приватного свойства.
        if(typeof(age) === 'number' && age > 0 && age < 110) {
            this._age = age;
        } else {
            console.log('недопустимое значение');
        }
    }
    
}


const ivan = new User('ivan', 30);

console.log(ivan.age ); // 30
ivan.age = 99; // меняем свойство
console.log(ivan.age ); // 99
ivan.age = 112; // недопустимое значение

ivan.say(); // Имя пользователя:ivan, возраст:99

Ну вот и все. По сути все тоже самое, что и когда мы создавали свои функции, для получения и установки. Только это современный синтаксис с get и set. Теперь у нас есть отдельный метод, для изменеия значения и напрямую как раньше сделать это нельзя.