Давайте напишем класс Tank, у которого будет 2 метода: moveTo (переместисьВ) и fireTo (стельниВ). Реализацию методов пока не пишем, это просто заготовки:
class Tank { moveTo(x, y) { } fireTo(x, y) { } }
С помощью этого класса мы сможем создать хоть сотню танчиков с однотипным поведением: каждый из них сможет перемещаться в нужную точку и стрелять.
Пока у нас написан только класс, то есть по сути мы сделали чертеж танка, но самого танка у нас нет. Сделаем его. Новый объект создается с помощью команды new, написанной перед названием класса:
var tank = new Tank; //в переменной tank теперь объект класса Tank
Давайте теперь создадим новый танк и вызовем метод moveTo, чтобы танк переместился в нужную точку:
var tank = new Tank; tank.moveTo(10, 20); //командуем перемещение
Давайте сделаем два танка и каждый из них переместим в заданную точку:
var tank1 = new Tank; tank1.moveTo(10, 10); var tank2 = new Tank; tank2.moveTo(20, 20);
Пусть второй танк стрельнет в точку нахождения первого:
var tank1 = new Tank; //создаем первый танк tank1.moveTo(10, 10); //командуем перемещение в точку 10, 10 var tank2 = new Tank; //создаем второй танк tank2.fireTo(10, 10); //командуем выстрел в местонахождение первого
Пусть у каждого созданного танка будет еще и свойство ammunition. В нем мы будем хранить количество снарядов танка.
Давайте создадим новый танк и в момент создания положим в него 10 снарядов:
var tank = new Tank; tank.ammunition = 10;
При создании танка мы следующей строчкой на лету создали ему свойство ammunition. Теперь это свойство доступно внутри любого метода класса вот так: this.ammunition:
class Tank { fireTo() { //тут доступны снаряды через this.ammunition } }
В данном случае this указывает на объект нашего класса. То есть: если мы вызываем метод fireTo для первого танчика, то this будет указывать на него, а если для второго танчика - то на него.
Давайте при каждом выстреле будем уменьшать количество снарядов на один:
class Tank { fireTo() { this.ammunition = this.ammunition - 1; //уменьшаем количество снарядов } }
Иногда нам может потребоваться вызывать метод одного класса внутри другого. К примеру, мы хотим сделать метод moveAndFire, который будет перемещать танк и одновременно делать выстрел. Но у нас уже есть методы moveTo и fireTo - используем их внутри нового метода, чтобы избежать дублирования кода.
Для этого также, как и при работе со свойствами, к методам следует обратиться через this, вот так: this.moveTo() и this.fireTo:
class Tank { moveTo(x, y) { } fireTo(x, y) { } moveAndFire(moveX, moveY, fireX, fireY) { this.moveTo(moveX, moveY); this.fireTo(fireX, fireY); } }
Конструктор
Мы задавали количество снарядов в танке при создании:
var tank = new Tank; tank.ammunition = 10; //количество снарядов
На самом деле это не очень удобно, ведь эту строчку легко забыть написать - и танк будет безоружен. Лучше было бы, чтобы танк уже в момент создания был обеспечен нужным количеством снарядов.
Исправить это проблему нам поможет метод-конструктор. Этот метод имеет стандартное название constructor и вызывается автоматически в момент создания объекта (когда мы пишем new).
Давайте создадим танк и в момент создания выведем что-нибудь алертом на экран:
class Tank { constructor() { alert('создание'); } } var tank = new Tank; //выведет 'создание'
Так же, как и в остальные методы, в конструктор можно передавать параметры. Давайте передадим в него параметр message и выведем его содержимое алертом на экран:
class Tank { constructor(message) { alert(message+'!'); } } var tank = new Tank('создание'); //выведет 'создание!'
Давайте теперь исправим описанное выше неудобство - пусть количество снарядов задается прямо в конструкторе:
class Tank { constructor() { this.ammunition = 10; //положим 10 снарядов в момент создания } fireTo(x, y) { this.ammunition = this.ammunition - 1; } }
Теперь каждый созданный танк будет иметь 10 снарядов уже в момент создания. Убедимся в этом:
var tank = new Tank; alert(tank.ammunition); //выведет 10
А еще лучше давайте сделаем параметр, в который будем передавать количество снарядов в момент создания танка, вот так:
var tank = new Tank(10); //создаем танк с 10-ю снарядами alert(tank.ammunition); //выведет '10'
Для этого в конструкторе напишем параметр ammunition, вот так: constructor(ammunition). Этот ammunition будет содержать в себе десятку, которую мы передаем в момент создания.
При этом переменная ammunition будет локальной переменной внутри конструктора. В данном случае нам это не нужно - мы хотели бы, чтобы количество снарядов было доступно во всех других методах (вот так: this.ammunition), а также снаружи объекта (вот так: tank.ammunition).
Для этого давайте запишем содержимое переменной ammunition в свойство ammunition, вот так: this.ammunition = ammunition.
Реализуем указанное:
class Tank { constructor(ammunition) { this.ammunition = ammunition; //запишем 10-тку в свойство объекта } fireTo(x, y) { this.ammunition = this.ammunition - 1; } }
С помощью этого кода мы можем создать танк, положить в него нужно количество снарядов, а также пострелять с помощью метода fireTo.
Вот этот код:
class Tank { constructor(ammunition) { this.ammunition = ammunition; } fireTo(x, y) { this.ammunition = this.ammunition - 1; } } var tank = new Tank(10); //создаем танк tank.fireTo(10, 20); //командуем выстрел
Если мы немного постреляем - с каждым выстрелом количество снарядов будет уменьшаться:
var tank = new Tank(10); alert(tank.ammunition); //выведет '10' tank.fireTo(10, 20); //скомандуем выстрел alert(tank.ammunition); //выведет '9' tank.fireTo(10, 20); //скомандуем выстрел alert(tank.ammunition); //выведет '8'
Есть проблема: если выстрелить более 10 раз, то танк не перестанет стрелять - он будет выводить 0, -1, -2 и так далее. Все потому, что мы не запрещаем выстрел, если количество снарядов достигло нуля.
Давайте реализуем вспомогательный метод canFire(), который будет проверять, не закончились ли снаряды:
class Tank { constructor(ammunition) { this.ammunition = ammunition; } fireTo() { //Перед выстрелом проверяем снаряды: if (this.canFire()) { this.ammunition = this.ammunition - 1; } } //Вспомогательный метод для проверки снарядов: canFire(ammunition) { if (ammunition > 0) { return true; } else { return false; } } }
Всем методам и свойствам, которые не должны быть видны снаружи, в начале названия добавляется подчеркивание (знак _). Давайте переименуем метод canFire в _canFire:
class Tank { constructor() { this.ammunition = 10; } fireTo() { if (this._canFire()) { this.ammunition = this.ammunition - 1; } } _canFire(ammunition) { if (ammunition > 0) { return true; } else { return false; } } }