TypeScript
Klasy
Szukaj…
Wprowadzenie
TypeScript, podobnie jak ECMA Script 6, obsługuje programowanie obiektowe za pomocą klas. Kontrastuje to ze starszymi wersjami JavaScript, które wspierały tylko prototypowy łańcuch dziedziczenia.
Obsługa klas w TypeScript jest podobna do obsługi języków takich jak Java i C #, ponieważ klasy mogą dziedziczyć z innych klas, podczas gdy obiekty są tworzone jako instancje klas.
Podobnie do tych języków, klasy TypeScript mogą implementować interfejsy lub korzystać z ogólnych.
Prosta klasa
class Car {
public position: number = 0;
private speed: number = 42;
move() {
this.position += this.speed;
}
}
W tym przykładzie deklarujemy prosty Car
klasy. Klasa ma trzech członków: speed
własności prywatnej, position
własności publicznej i move
metody publicznej. Pamiętaj, że każdy członek jest domyślnie publiczny. Dlatego move()
jest publiczny, nawet jeśli nie użyliśmy public
słowa kluczowego.
var car = new Car(); // create an instance of Car
car.move(); // call a method
console.log(car.position); // access a public property
Podstawowe dziedziczenie
class Car {
public position: number = 0;
protected speed: number = 42;
move() {
this.position += this.speed;
}
}
class SelfDrivingCar extends Car {
move() {
// start moving around :-)
super.move();
super.move();
}
}
Ten przykład pokazuje, jak utworzyć bardzo prostą podklasę klasy Car
za pomocą słowa kluczowego extends
. Klasa SelfDrivingCar
przesłania metodę move()
i używa implementacji klasy podstawowej za pomocą super
.
Konstruktory
W tym przykładzie używamy constructor
aby zadeklarować position
własności publicznej i speed
właściwości chronionej w klasie podstawowej. Te właściwości nazywane są właściwościami parametrów . Pozwalają nam zadeklarować parametr konstruktora i członka w jednym miejscu.
Jedną z najlepszych rzeczy w TypeScript jest automatyczne przypisywanie parametrów konstruktora do odpowiedniej właściwości.
class Car {
public position: number;
protected speed: number;
constructor(position: number, speed: number) {
this.position = position;
this.speed = speed;
}
move() {
this.position += this.speed;
}
}
Cały ten kod można wznowić w jednym konstruktorze:
class Car {
constructor(public position: number, protected speed: number) {}
move() {
this.position += this.speed;
}
}
Oba zostaną przetransponowane z TypeScript (czas projektowania i czas kompilacji) na JavaScript z tym samym wynikiem, ale pisząc znacznie mniej kodu:
var Car = (function () {
function Car(position, speed) {
this.position = position;
this.speed = speed;
}
Car.prototype.move = function () {
this.position += this.speed;
};
return Car;
}());
Konstruktory klas pochodnych muszą wywoływać konstruktor klasy podstawowej za pomocą super()
.
class SelfDrivingCar extends Car {
constructor(startAutoPilot: boolean) {
super(0, 42);
if (startAutoPilot) {
this.move();
}
}
}
let car = new SelfDrivingCar(true);
console.log(car.position); // access the public property position
Akcesoria
W tym przykładzie zmodyfikujemy przykład „Klasa prosta”, aby umożliwić dostęp do właściwości speed
. Akcesorium maszynopisu pozwala nam dodawać dodatkowy kod do programów pobierających lub ustawiających.
class Car {
public position: number = 0;
private _speed: number = 42;
private _MAX_SPEED = 100
move() {
this.position += this._speed;
}
get speed(): number {
return this._speed;
}
set speed(value: number) {
this._speed = Math.min(value, this._MAX_SPEED);
}
}
let car = new Car();
car.speed = 120;
console.log(car.speed); // 100
Klasy abstrakcyjne
abstract class Machine {
constructor(public manufacturer: string) {
}
// An abstract class can define methods of it's own, or...
summary(): string {
return `${this.manufacturer} makes this machine.`;
}
// Require inheriting classes to implement methods
abstract moreInfo(): string;
}
class Car extends Machine {
constructor(manufacturer: string, public position: number, protected speed: number) {
super(manufacturer);
}
move() {
this.position += this.speed;
}
moreInfo() {
return `This is a car located at ${this.position} and going ${this.speed}mph!`;
}
}
let myCar = new Car("Konda", 10, 70);
myCar.move(); // position is now 80
console.log(myCar.summary()); // prints "Konda makes this machine."
console.log(myCar.moreInfo()); // prints "This is a car located at 80 and going 70mph!"
Klasy abstrakcyjne to klasy podstawowe, od których mogą się rozciągać inne klasy. Nie można ich utworzyć samodzielnie (tzn. Nie można zrobić new Machine("Konda")
).
Dwie kluczowe cechy abstrakcyjnej klasy w Typescript to:
- Mogą wdrażać własne metody.
- Mogą definiować metody, które muszą implementować dziedziczące klasy.
Z tego powodu klasy abstrakcyjne można koncepcyjnie uznać za połączenie interfejsu i klasy .
Monkey łata funkcję do istniejącej klasy
Czasami przydaje się możliwość rozszerzenia klasy o nowe funkcje. Załóżmy na przykład, że łańcuch powinien zostać przekształcony w łańcuch wielkości wielbłąda. Musimy więc powiedzieć TypeScript, że String
zawiera funkcję o nazwie toCamelCase
, która zwraca string
.
interface String {
toCamelCase(): string;
}
Teraz możemy wstawić tę funkcję do implementacji String
.
String.prototype.toCamelCase = function() : string {
return this.replace(/[^a-z ]/ig, '')
.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, (match: any, index: number) => {
return +match === 0 ? "" : match[index === 0 ? 'toLowerCase' : 'toUpperCase']();
});
}
Jeśli to rozszerzenie String
jest załadowane, można je wykorzystać w następujący sposób:
"This is an example".toCamelCase(); // => "thisIsAnExample"
Transpilacja
Biorąc pod uwagę klasę SomeClass
, zobaczmy, w jaki sposób TypeScript jest transpilowany na JavaScript.
Źródło TypeScript
class SomeClass {
public static SomeStaticValue: string = "hello";
public someMemberValue: number = 15;
private somePrivateValue: boolean = false;
constructor () {
SomeClass.SomeStaticValue = SomeClass.getGoodbye();
this.someMemberValue = this.getFortyTwo();
this.somePrivateValue = this.getTrue();
}
public static getGoodbye(): string {
return "goodbye!";
}
public getFortyTwo(): number {
return 42;
}
private getTrue(): boolean {
return true;
}
}
Źródło JavaScript
Po transpilacji za pomocą TypeScript v2.2.2
dane wyjściowe wyglądają tak:
var SomeClass = (function () {
function SomeClass() {
this.someMemberValue = 15;
this.somePrivateValue = false;
SomeClass.SomeStaticValue = SomeClass.getGoodbye();
this.someMemberValue = this.getFortyTwo();
this.somePrivateValue = this.getTrue();
}
SomeClass.getGoodbye = function () {
return "goodbye!";
};
SomeClass.prototype.getFortyTwo = function () {
return 42;
};
SomeClass.prototype.getTrue = function () {
return true;
};
return SomeClass;
}());
SomeClass.SomeStaticValue = "hello";
Spostrzeżenia
- Modyfikacja prototypu klasy jest zapakowana w IIFE .
- Zmienne składowe są zdefiniowane w głównej
function
klasy. - Właściwości statyczne są dodawane bezpośrednio do obiektu klasy, podczas gdy właściwości instancji są dodawane do prototypu.