private и public
Любой код может изменить любое поле объекта. Достаточно одной небрежной строки где-нибудь в игре — и у Киры отрицательное золото:
class Hero {
name: string;
gold: number = 0;
constructor(name: string) {
this.name = name;
}
earn(amount: number): void {
this.gold = this.gold + amount;
}
}
const kira = new Hero("Кира");
kira.earn(50);
kira.gold = kira.gold - 80; // покупает меч за 80 золотых
console.log(`${kira.name}: золото ${kira.gold}`);Программа выводит:
Кира: золото -30Класс должен охранять своё золото: менять его должны только собственные методы, а они могут проверять правила. Пометьте поле как private:
class Hero {
name: string;
private gold: number = 0;
constructor(name: string) {
this.name = name;
}
earn(amount: number): void {
this.gold = this.gold + amount;
}
spend(amount: number): boolean {
if (amount > this.gold) {
return false;
}
this.gold = this.gold - amount;
return true;
}
getGold(): number {
return this.gold;
}
}
const kira = new Hero("Кира");
kira.earn(50);
console.log(kira.spend(80));
console.log(kira.spend(30));
console.log(`${kira.name}: золото ${kira.getGold()}`);Программа выводит:
false
true
Кира: золото 20Поле private можно использовать только внутри класса, в его методах, через this. Код вне класса не может ни прочитать такое поле, ни изменить. Добавьте в конец программы kira.gold = 1000;, и TypeScript сообщит:
main.ts(31,6): error TS2341: Property 'gold' is private and only accessible within class 'Hero'.Остальная игра добирается до золота через методы, а они соблюдают правила: spend возвращает false и ничего не меняет, если золота не хватает, а getGold позволяет другим прочитать золото, но не изменить его. Поля и методы без private — публичные (public): ими может пользоваться кто угодно. Так сделано по умолчанию. public можно написать и явно (public name: string;), но в большинстве кода так не делают.
Как и readonly в уроке «Типы объектов», private проверяет только TypeScript. В JavaScript gold — обычное свойство, и console.log(kira) по-прежнему его показывает: Hero { name: "Кира", gold: 20 }. У самого JavaScript тоже есть приватные поля, имена которых начинаются с # (#gold); они остаются скрытыми, даже пока программа работает. В чужом коде вы встретите оба вида; в этом курсе используется private.
Типичные ошибки: читать приватное поле снаружи класса (добавьте метод, который его возвращает, как getGold) и делать приватным метод, который нужен остальной программе.
Задание
- 1
Запустите программу: у Лены получается отрицательная мана. Добавьте метод
cast(cost: number): boolean: если у мага маны меньше, чемcost, он возвращаетfalseи ничего не меняет; иначе вычитаетcostизmanaи возвращаетtrue. Замените обе строки, меняющиеlena.mana, наconsole.log(lena.cast(15));. Программа выводит:true false Лена: мана 5 - 2
Чтобы никто не мог обойти
cast, сделайтеmanaприватным полем: напишитеprivateперед полем. Тогда TypeScript отметит последнюю строку, которая читаетlena.manaснаружи класса. Добавьте методgetMana(): numberи используйте его в этой строке. Программа выводит то же, что и раньше.