在ES6之前,JS沒有class關(guān)鍵字,JS的面向?qū)ο蠛屠^承也是面試中常見的問題.之前接觸過PHP面向?qū)ο蟮脑?在看這部分內(nèi)容會(huì)覺得很多相近相似的內(nèi)容
1.類
類是描述一類相同事物特征和行為的抽象.描述一個(gè)類需要兩部分,屬性描述特征,方法描述行為,并且用class來(lái)修飾,這樣構(gòu)成了一個(gè)類,類相當(dāng)于提供了一個(gè)模板,快速的根據(jù)模板創(chuàng)建的對(duì)象.先看一個(gè)類的例子
class Person{
name:string;
constructor(name:string) {
this.name = name;
}
sayHi(){
return this.name;
}
}
name是屬性,constructor是構(gòu)造函數(shù),構(gòu)造函數(shù)在JS的面向?qū)ο罄镆泊嬖?初始化對(duì)象自定義內(nèi)容的函數(shù),sayHi是方法,方法里返回name屬性的內(nèi)容,整體寫法跟JS的面向?qū)ο箢愃?獲取值的時(shí)候也是使用this關(guān)鍵字.接下來(lái)看一下解析的.js文件里的內(nèi)容
var Person = (function () {
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function () {
return this.name;
};
return Person;
}());
使用的就是JS的構(gòu)造函數(shù),在原型上添加了一個(gè)sayHi方法,還是比較好理解的
2.繼承
TypeScript里的繼承跟PHP還是比較相似的,相當(dāng)于是子類對(duì)父類進(jìn)行功能和內(nèi)容的擴(kuò)張,使用的關(guān)鍵字也是extends,延展.
// 父類
class Person{
name:string;
constructor(name: string) {
this.name = name;
}
move(meter: number = 0) {
console.log(\`${this.name} moved ${meter}m.\`);
}
}
// 子類
class Student extends Person {
age:number;
constructor(name: string, age:number) {
super(name);
this.age = age;
}
move(meter = 5) {
console.log("測(cè)試...");
super.move(meter);
}
}
Student繼承父類Person,子類會(huì)繼承父類所有特征和行為,子類的構(gòu)造函數(shù)里,如果子類和父類同時(shí)聲明構(gòu)造函數(shù),子類創(chuàng)建對(duì)象的時(shí)候優(yōu)先使用自己類里的構(gòu)造函數(shù),如果還想使用父類的構(gòu)造函數(shù),需要在子類的構(gòu)造函數(shù)里使用super(),而且這句話要放在子類構(gòu)造函數(shù)的最上面,否則會(huì)報(bào)錯(cuò),只有構(gòu)造函數(shù)需要注意這個(gè)問題.
代碼里演示了子類重寫了繼承過來(lái)的move方法,如果還想調(diào)用父類功能,可以在方法里視同super.move(),通過super來(lái)調(diào)用父類的方法,保留功能.
3.修飾符
修飾符的作用就是用來(lái)限制屬性和方法使用的范圍,有三種修飾符,公有public,私有private,被保護(hù)的protected
1.public 公有的
方法和屬性默認(rèn)的修飾符就是public,對(duì)象在使用它修飾的屬性和方法時(shí),可以直接在用.的方式進(jìn)行調(diào)用,使用范圍是最大的
class Person{
public name:string;
constructor(name: string) { this.name = name; }
public move(meter: number = 0) {
console.log(\`${this.name} moved ${meter}m.\`);
}
}
2.被保護(hù)的 protected
被protected修飾的屬性和方法,限制了屬性和方法的使用范圍,只能在類和子類中使用,如果在類外部調(diào)用,會(huì)報(bào)錯(cuò)
class Person{
protected name:string;
constructor(name: string) { this.name = name; }
protected move(meter: number = 0) {}
}
class Student extends Person {
age:number;
constructor(name: string, age:number) {
super(name);
this.age = age;
}
move(meter = 5) {
super.move();
console.log(this.name); // 子類的內(nèi)部可以使用
}
}
let an = new Person("張三");
an.move(); // 報(bào)錯(cuò),在類的外部使用
類的內(nèi)部,就值在類對(duì)應(yīng)的大括號(hào)里,protected修飾的屬性方法可以使用,這樣限制了屬性和方法的使用范圍,使用受限,相對(duì)的安全性更好
3.私有的 private
private的使用范圍更小了,被限制到只能在自己類的內(nèi)容使用,連子類都不能使用,當(dāng)時(shí)private是使用最多的,因?yàn)樽畲蠡臏p少了使用范圍,能更好規(guī)避一些不必要的使用出現(xiàn)的問題,更安全
class Person{
private name:string;
constructor(name: string) { this.name = name; }
private move(meter: number = 0) {}
}
class Student extends Person {
age:number;
constructor(name: string, age:number) {
super(name);
this.age = age;
}
move(meter = 5) {
super.move(); // 報(bào)錯(cuò),子類的內(nèi)部也不能使用
console.log(this.name); // 報(bào)錯(cuò),子類的內(nèi)部也不能使用
}
}
當(dāng)這樣的類創(chuàng)建的對(duì)象,想獲取屬性的值的時(shí)候,需要用setters和getters對(duì)屬性進(jìn)行操作
<pre>
class Person{
private _name:string;
constructor(name: string) { this.name = name; }
set name(newName:string){
this._name = newName;
}
get name(){
return this._name;
}
}
let per = new Person("張三");
per.name = "龍哥";
console.log(per.name);
</pre>
在使用設(shè)置器setters和訪問器getters時(shí),屬性名會(huì)習(xí)慣的加一個(gè)下劃線,用來(lái)和另個(gè)方法名進(jìn)行區(qū)分,這種方式和iOS里的屬性寫法一樣,對(duì)象可以直接使用,用法跟之前一樣,只不過本質(zhì)是用函數(shù)來(lái)賦值.在使用的時(shí)候需要注意,編譯器至少是ES5或者更高,否則會(huì)報(bào)錯(cuò)
4.靜態(tài)屬性
之前的屬性都是由對(duì)象來(lái)使用,必須實(shí)例化之后,才能使用.靜態(tài)屬性不同,這類屬性都用在類本身上.用static關(guān)鍵詞來(lái)修飾
<pre>
class Grid {
static origin = {x: 100, y: 10};
test():void{
console.log(Grid.origin.x);
}
}
let obj = new Grid();
obj.test();
console.log(Grid.origin.x);
console.log(obj.origin.x); // 報(bào)錯(cuò),對(duì)象不能使用靜態(tài)屬性
</pre>
5.抽象類
抽象類一般作為其他派生類的基類使用,如果通過這個(gè)類進(jìn)行對(duì)象創(chuàng)建,在控制臺(tái)會(huì)報(bào)錯(cuò),內(nèi)容就是在對(duì)一個(gè)抽象類進(jìn)行實(shí)例化操作.抽象類用關(guān)鍵詞abstract進(jìn)行修飾,抽象類里的正常方法具體的實(shí)現(xiàn),用abstract修飾的抽象方法需要在子類中實(shí)現(xiàn).抽象類跟接口類似,都是定義方法簽名,不包含方法體.
<pre>
abstract class Person {
constructor(public name: string) {}
printName(): void {
console.log('name: ' + this.name);
}
abstract printMeeting(): void; // 必須在派生類中實(shí)現(xiàn)
}
class Animal extends Person {
constructor(name:string) {
super(name);
}
printMeeting(): void {
console.log('嗯嗯');
}
generateReports(): void {
console.log('餓了');
}
}
let an = new Animal("龍哥");
an.printMeeting();
console.log(an.name);
</pre>