相關概念
- 類(Class):定義了一件事物的抽象特點,包含它的屬性和方法
- 對象(Object):類的實例,通過
new
生成 - 面向對象(OOP)的三大特性:封裝、繼承、多態
- 封裝(Encapsulation):將對數據的操作細節隱藏起來,只暴露對外的接口。外界調用端不需要(也不可能)知道細節,就能通過對外提供的接口來訪問該對象,同時也保證了外界無法任意更改對象內部的數據
- 繼承(Inheritance):子類繼承父類,子類除了擁有父類的所有特性外,還有一些更具體的特性
- 多態(Polymorphism):由繼承而產生了相關的不同的類,對同一個方法可以有不同的響應。比如
Cat
和Dog
都繼承自Animal
,但是分別實現了自己的eat
方法。此時針對某一個實例,我們無需瞭解它是Cat
還是Dog
,就可以直接調用eat
方法,程序會自動判斷出來應該如何執行eat
- 存取器(getter & setter):用以改變屬性的讀取和賦值行爲
- 修飾符(Modifiers):修飾符是一些關鍵字,用於限定成員或類型的性質。比如
public
表示公有屬性或方法 - 抽象類(Abstract Class):抽象類是供其他類繼承的基類,抽象類不允許被實例化。抽象類中的抽象方法必須在子類中被實現
- 接口(Interfaces):不同類之間公有的屬性或方法,可以抽象成一個接口。接口可以被類實現(implements)。一個類只能繼承自另一個類,但是可以實現多個接口
作者:MrWelson
鏈接:https://www.jianshu.com/p/ae672b7a26e3
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
es6類
TypeScript 是面向對象的 JavaScript。
類描述了所創建的對象共同的屬性和方法。
TypeScript 支持面向對象的所有特性,比如 類、接口等。
TypeScript 類定義方式如下:
class class_name {
// 類作用域
}
定義類的關鍵字爲 class,後面緊跟類名,類可以包含以下幾個模塊(類的數據成員):
-
字段 − 字段是類裏面聲明的變量。字段表示對象的有關數據。
-
構造函數 − 類實例化時調用,可以爲類的對象分配內存。
-
方法 − 方法爲對象要執行的操作。
使用 class
定義類,使用 constructor
定義構造函數。
通過 new
生成新實例的時候,會自動調用構造函數。
this 關鍵字表示當前類實例化的對象。注意構造函數的參數名與字段名相同。
class Animal {
userName: string; // 定義屬性
constructor(name) { // 定義構造函數對實例進行初始化
this.userName = name; // 屬性賦值
};
sayHi() { // 定義方法
return `My name is ${this.userName}`;
}
}
/**
* 創建實例化對象
* 我們使用 new 關鍵字來實例化類的對象,語法格式如下:
* var object_name = new class_name([ arguments ])
*/
let cat = new Animal('Tom');
console.log(cat.sayHi()); //My name is Tom
類的繼承
TypeScript 支持繼承類,即我們可以在創建類的時候繼承一個已存在的類,這個已存在的類稱爲父類,繼承它的類稱爲子類。
類繼承使用關鍵字 extends,子類除了不能繼承父類的私有成員(方法和屬性)和構造函數,其他的都可以繼承。
TypeScript 一次只能繼承一個類,不支持繼承多個類,但 TypeScript 支持多重繼承(A 繼承 B,B 繼承 C)。
語法格式如下:
class child_class_name extends parent_class_name
繼承類的方法重寫
類繼承後,子類可以對父類的方法重新定義,這個過程稱之爲方法的重寫。
其中 super 關鍵字是對父類的直接引用,該關鍵字可以引用父類的屬性和方法。
// 類的繼承
class Cat extends Animal {
color: string;
constructor(name,color) {
super(name); // 調用父類Animal的 contructor(name)
this.color = color;
};
sayHi() {
// super.sayHi():調用父類的 sayHi()
return super.sayHi() + '我是一隻' + this.color + '色的貓';
}
}
let cat2 = new Cat('Tom','橘黃');
console.log(cat2.sayHi()); //My name is Tom我是一隻橘黃色的貓
let cat3 = new Cat('Jerry','yellow');
cat3.color = '黃'
console.log(cat3.sayHi()); //My name is Jerry我是一隻黃色的貓
存取器
使用 getter 和 setter 可以改變屬性的賦值和讀取行爲:
class Animal2{
userName: string;
constructor(name) {
this.userName = name;
};
get userName() {
return 'muzidigbig';
};
set userName(value) {
console.log('setter: ' + value);
}
}
let a = new Animal2('Kitty'); // setter: Kitty
a.userName = 'Tom';// setter: Tom
console.log(a.userName);// muzidigbig
實例屬性和方法
js中的屬性和方法:
// js中
function Person(name) {
this.name = name; // 實例屬性
this.eat = function(){ console.log('eat') }; // 實例方法
}
Person.age = 19; // 靜態屬性
Person.sleep = function(){ console.log('sleep') }; // 靜態方法
// 訪問實例方法和屬性:
var tom = new Person('tom');
console.log(tom.name) // tom
tom.eat();
tom.sleep() // error: tom.sleep is not a function
// 訪問靜態方法和屬性:
console.log(Person.age); // 19
Person.sleep();
Person.eat(); // error: Person.eat is not a function
ES6 中實例的屬性只能通過構造函數中的 this.xxx
來定義:
class Animal {
constructor(){
this.name = 'tom';
}
eat() {}
}
let a = new Animal();
console.log(a.name); // tom
ES7 提案中可以直接在類裏面定義:
// ts
class Animal {
name = 'tom';
eat() {}
}
let a = new Animal();
console.log(a.name); // Jack
靜態屬性和方法
ES7 提案中,可以使用 static
定義一個靜態屬性或方法。靜態方法不需要實例化,而是直接通過類來調用:
// ts
class Animal {
static num = 42;
static isAnimal(a) {
return a instanceof Animal;
}
}
console.log(Animal.num); // 42
let a = new Animal('Jack');
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function
訪問修飾符
public
公有屬性或方法,可以在任何地方被訪問到,默認所有的屬性和方法都是 public
的
private
私有屬性或方法,不能在聲明它的類的外部訪問,也不可以在子類中訪問
protected
受保護的屬性或方法,它和 private
類似,區別是它可以在子類中訪問
// 訪問修飾符
class Person {
public name: string;
private idCard: number;
protected phone: number;
constructor (name,idCard,phone) {
this.name = name;
this.idCard = idCard;
this.phone = phone;
}
}
let tom = new Person('Tom',42000,13986358544);
console.log(tom.name); // Tom
// console.log(tom.idCard);//error TS2341: Property 'idCard' is private and only accessible within class 'Person'.
// console.log(tom.phone); //error TS2445: Property 'phone' is protected and only accessible within class 'Person' and its subclasses.
class Teacher extends Person {
constructor(name,idCard,phone) {
super(name,idCard,phone);
console.log(this.name);
console.log(this.phone);
// console.log(this.idCard); //error TS2341: Property 'idCard' is private and only accessible within class 'Person'.
}
}
多態
同一個父類的多個子類,可以有不同結果的同名方法
class Person {
eat(){ console.log('eat') }
}
class A extends Person {
eat(){ console.log('A eat') }
}
class B extends Person {
eat(){ console.log('B eat') }
}
抽象類/抽象方法 abstract
abstract
用於定義抽象類和其中的抽象方法。
- 抽象類是提供給其他類繼承的基類(父類),是不允許被實例化
- 抽象方法只能包含在抽象類中
- 子類繼承抽象類,必須實現抽象類中的抽象方法
abstract class Animal {
abstract eat(); // 抽象方法
// 普通方法
sleep(){
console.log('sleep')
}
}
let a = new Animal(); // 報錯,抽象類不能被實例化
class Cat extends Animal {
eat(){
// 父類的eat方法必須被實現
console.log('eat')
}
}
類與接口
類可以實現接口。
前面介紹了 接口 可以用來描述 對象(object)的形狀,這一章主要介紹 接口 對 類(class)的行爲 進行抽象。
類實現接口 implements
實現(implements)是面向對象中的一個重要概念。一個類只能繼承自另一個類,不同類之間可能會有一些共有特性,提取多個類的共有特性,作爲一個接口,再用 implements
關鍵字來實現就可以大大提高面向對象的靈活性。
舉例: 人是一個類,人需要吃東西。動物是一個類,動物也需要吃東西。這種情況就可以把 吃東西 提取出來作爲一個接口:
interface Ieat {
eat();
}
class Person implements Ieat{
eat(){}
}
class Animal implements Ieat {
eat(){}
}