От автора: TypeScript — это объектно-ориентированный JavaScript. TypeScript поддерживает такие функции объектно-ориентированного программирования как классы, интерфейсы и так далее. Класс в контексте ООП — это макет для создания объектов. Класс инкапсулирует данные для объекта. Typescript предоставляет встроенную поддержку классов. JavaScript ES5 или более ранние этого не делали. В Typescript классы поддерживаются, он получил эту функцию от ES6.
Создание классов
Чтобы объявить в TypeScript класс, нужно использовать ключевое слово class. Синтасис для него приведён ниже:
Синтаксис
1 2 3 |
class class_name { //область класса } |
После ключевого слова class следует имя класса. Когда вы называете класс, нужно учитывать правила идентификаторов. Определение класса может включать следующее:
Поля − Поле — это любая переменная, объявленная в классе. Поля представляют данные, принадлежащие объектам.
Конструкторы − Отвечают за присвоение памяти объектам класса.
Функции − Функции представляют действия, которые может предпринять объект.. Иногда они также рассматриваются, как методы.
Вместе эти компоненты именуются членами данных класса. Рассмотрим класс Person в typescript.
1 2 |
class Person { } |
После компиляции мы получим следующий JavaScript код:
1 2 3 4 5 6 |
//Сгенерировано посредством typescript 1.8.10 var Person = (function () { function Person() { } return Person; }()); |
Пример: Объявление класса
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Car { //поле engine:string; //конструктор constructor(engine:string) { this.engine = engine } //функция disp():void { console.log("Engine is : "+this.engine) } } |
Здесь мы объявляем класс Car. Этот класс имеет поле под названием engine. Ключевое слово var не используется во время объявления поля. Вышеприведённый пример объявляет конструктор для класса.
Конструктор — это специальная функция класса, ответственная за инициализацию переменных класса. TypeScript определяет конструктор используя ключевое слово constructor. Конструктор — это функция, а значит она может быть параметризованной.
Ключевое слово this обозначает текущий экземпляр класса. В нашем случае имя параметра и имя поля класса одинаковы. В результате, чтобы избежать неоднозначности, к полю класса добавляется префикс — ключевое слово this.
disp() — это простое определение функции. Учтите, что в этой ситуации не используется ключевое слово function. После компиляции мы получим следующий JavaScript код:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//Сгенерировано посредством typescript 1.8.10 var Car = (function () { //конструктор function Car(engine) { this.engine = engine; } //функция Car.prototype.disp = function () { console.log("Engine is : " + this.engine); }; return Car; }()); |
Создание объектов-экземпляров
Чтобы создать экземпляр класса, используйте ключевое слово new, после которого следует имя класса. Синтасис для него приведён ниже:
Синтаксис
1 |
var object_name = new class_name([ arguments ]) |
Ключевое слово new отвечает за конкретизацию.
Правая сторона выражения вызывает конструктор. Если конструктор параметризованный, то ему должны быть переданы значения.
Пример: конкретизация класса
1 |
var obj = new Car("Engine 1") |
Доступ к атрибутам и функциям
Получить доступ к атрибутам и функциям класса можно через объект. Используйте точечную нотацию «.» (точку), чтобы получить доступ к членам данных класса.
1 2 3 4 5 |
//получения доступа к атрибуту obj.field_name //получения доступа к функции obj.function_name() |
Пример: складываем все вместе
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Car { //поле engine:string; //конструктор constructor(engine:string) { this.engine = engine } //функция disp():void { console.log("Function displays Engine is : "+this.engine) } } //создаём объект var obj = new Car("XXSY1") //получаем доступ к полю console.log("Reading attribute value Engine as : "+obj.engine) //получаем доступ к функции obj.disp() |
После компиляции мы получим следующий код JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//Сгенерировано посредством typescript 1.8.10 var Car = (function () { //конструктор function Car(engine) { this.engine = engine; } //функция Car.prototype.disp = function () { console.log("Function displays Engine is : " + this.engine); }; return Car; }()); //создаём объект var obj = new Car("XXSY1"); //получаем доступ к полю console.log("Reading attribute value Engine as : " + obj.engine); //получаем доступ к функции obj.disp(); |
Результат выглядит следующим образом:
1 2 |
Reading attribute value Engine as : XXSY1 Function displays Engine is : XXSY1 |
Наследование класса
TypeScript поддерживает наследование. Наследование — это способность программы создавать новые классы из уже существующего класса. Класс, расширенный, чтобы создать новые классы, называется родительным классом / супер классом. Новые классы называются дочерними классами / подклассами.
Класс наследует от другого класса используя ключевое слово extends. Дочерние классы наследуют от родительного класса все свойства и методы, кроме скрытых членов и конструкторов.
Синтаксис
1 |
class child_class_name extends parent_class_name |
Однако, TypeScript не поддерживает множественное наследование. Пример: Наследование класса
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Shape { Area:number constructor(a:number) { this.Area = a } } class Circle extends Shape { disp():void { console.log("Area of the circle: "+this.Area) } } var obj = new Circle(223); obj.disp() |
После компиляции мы получим следующий код JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//Сгенерировано посредством typescript 1.8.10 var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var Shape = (function () { function Shape(a) { this.Area = a; } return Shape; }()); var Circle = (function (_super) { __extends(Circle, _super); function Circle() { _super.apply(this, arguments); } Circle.prototype.disp = function () { console.log("Area of the circle: " + this.Area); }; return Circle; }(Shape)); var obj = new Circle(223); obj.disp(); |
Результат выглядит следующим образом:
1 |
Area of the Circle: 223 |
В приведённом выше примере мы объявляем класс Shape. Этот класс расширен с помощью класса Circle. Поскольку классы находятся в отношениях наследования, дочерний класс, то есть класс Car получает неявный доступ к атрибуту его родительного класса, то есть area. Наследование может быть:
Единичным − Каждый класс может расширяться только от одного родительного класса
Множественным − Класс может наследоваться от множества классов. TypeScript не поддерживает множественное наследование.
Многоуровневое − Следующий пример демонстрирует принцип многоуровневого наследования.
Пример
1 2 3 4 5 6 7 8 9 10 |
class Root { str:string; } class Child extends Root {} class Leaf extends Child {} //косвенно наследует от Root в силу действия наследования var obj = new Leaf(); obj.str ="hello" console.log(obj.str) |
Класс Leaf выводит атрибуты из классов Root и Child в силу действия многоуровневого наследования. После компиляции мы получим следующий код JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//Сгенерировано посредством typescript 1.8.10 var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var Root = (function () { function Root() { } return Root; }()); var Child = (function (_super) { __extends(Child, _super); function Child() { _super.apply(this, arguments); } return Child; }(Root)); var Leaf = (function (_super) { __extends(Leaf, _super); function Leaf() { _super.apply(this, arguments); } return Leaf; }(Child)); var obj = new Leaf(); obj.str = "hello"; console.log(obj.str); |
Результат выглядит следующим образом:
1 |
hello |
TypeScript ─ Наследование класса и предопределение методов
Предопределение методов — это механизм, благодаря которому дочерний класс предопределяет метод суперкласса. Следующий пример иллюстрирует этот механизм:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class PrinterClass { doPrint():void { console.log("doPrint() from Parent called…") } } class StringPrinter extends PrinterClass { doPrint():void { super.doPrint() console.log("doPrint() is printing a string…") } } var obj = new StringPrinter() obj.doPrint() |
Ключевое слово super используется для обозначения прямого родителя класса. Это ключевое слово можно использовать для обращения к версии переменной, свойства или метода супер класса. Строка 13 вызывает версию функции doWork() супер класса. После компиляции мы получим следующий код JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
//Сгенерировано посредством typescript 1.8.10 var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var PrinterClass = (function () { function PrinterClass() { } PrinterClass.prototype.doPrint = function () { console.log("doPrint() from Parent called…"); }; return PrinterClass; }()); var StringPrinter = (function (_super) { __extends(StringPrinter, _super); function StringPrinter() { _super.apply(this, arguments); } StringPrinter.prototype.doPrint = function () { _super.prototype.doPrint.call(this); console.log("doPrint() is printing a string…"); }; return StringPrinter; }(PrinterClass)); var obj = new StringPrinter(); obj.doPrint(); |
Результат выглядит следующим образом:
1 2 |
doPrint() from Parent called… doPrint() is printing a string… |
Ключевое слово static
Ключевое слово static можно применять к членам данных класса. Статическая переменная хранит его значения до тех пор, пока программа не закончит выполнение. Сослаться на статические члены можно с помощью имени класса. Пример
1 2 3 4 5 6 7 8 9 10 |
class StaticMem { static num:number; static disp():void { console.log("The value of num is"+ StaticMem.num) } } StaticMem.num = 12 // инициализируем статическую переменную StaticMem.disp() // вызываем статический метод |
После компиляции мы получим следующий код JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Сгенерировано посредством typescript 1.8.10 var StaticMem = (function () { function StaticMem() { } StaticMem.disp = function () { console.log("The value of num is" + StaticMem.num); }; return StaticMem; }()); StaticMem.num = 12; // инициализируем статическую переменную StaticMem.disp(); // вызываем статический метод |
Результат выглядит следующим образом:
1 |
The value of num is 12 |
Оператор instanceof
Оператор instanceof возвращает true , если объект принадлежит к указанному типу. Пример
1 2 3 4 |
class Person{ } var obj = new Person() var isPerson = obj instanceof Person; console.log(" obj is an instance of Person " + isPerson); |
После компиляции мы получим следующий JavaScript код:
1 2 3 4 5 6 7 8 9 10 |
//Сгенерировано посредством typescript 1.8.10 var Person = (function () { function Person() { } return Person; }()); var obj = new Person(); var isPerson = obj instanceof Person; console.log(" obj is an instance of Person " + isPerson); |
Результат выглядит следующим образом:
1 |
obj is an instance of Person True |
Скрытие данных
Класс может контролировать видимость его членов данных по отношению к членам других классов. Эта способность называется скрытием данных или инкапсуляцией.
Объектная ориентированность использует концепцию модификаторов или спецификаторов доступа, чтобы реализовать инкапсуляцию. Спецификаторы/модификаторы доступа определяют видимость членов данных класса вне определяющего их класса. Модификаторы доступа, поддерживаемые TypeScript:
публичные — Публичные члены данных имеют универсальную доступность. Члены данных в классе являются публичными по умолчанию.
закрытые — Закрытые члены данных доступны только внутри класса, который определяет эти члены. Если внешний член класса пытается получить доступ к закрытому члену, компилятор выдаёт ошибку.
защищённые — Защищённый член данных доступен для членов внутри того же класса, а также для членов дочерних классов.
Давайте рассмотрим на примере, как работает скрытие данных:
1 2 3 4 5 6 7 8 |
class Encapsulate { str:string = "hello" private str2:string = "world" } var obj = new Encapsulate() console.log(obj.str) //доступен console.log(obj.str2) //ошибка компиляции, так как str2 закрытый |
Этот класс имеет 2 атрибута строки: str1 и str2, которые являются публичными и закрытыми членами соответственно. Класс конкретизирован. Пример возвращает ошибку компиляции, так как к закрытому атрибуту str2 запрашивается доступ из-за пределов класса, который его объявляет.
Классы и интерфейсы
Классы также могут реализовать интерфейсы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
interface ILoan { interest:number } class AgriLoan implements ILoan { interest:number rebate:number constructor(interest:number,rebate:number) { this.interest = interest this.rebate = rebate } } var obj = new AgriLoan(10,1) console.log("Interest is : "+obj.interest+" Rebate is : "+obj.rebate ) |
Класс AgriLoan реализует интерфейсы Loan. В результате, класс обязательно должен включать свойство interest в качестве его члена. После компиляции мы получим следующий JavaScript код:
1 2 3 4 5 6 7 8 9 10 11 |
//Сгенерировано посредством typescript 1.8.10 var AgriLoan = (function () { function AgriLoan(interest, rebate) { this.interest = interest; this.rebate = rebate; } return AgriLoan; }()); var obj = new AgriLoan(10, 1); console.log("Interest is : " + obj.interest + " Rebate is : " + obj.rebate); |
Результат выглядит следующим образом:
1 |
Interest is : 10 Rebate is : 1 |
Источник: //www.tutorialspoint.com/
Редакция: Команда webformyself.