為什么需要類呢蓬坡?
- 外來(lái)人口多,迫切需要 class(以前是沒(méi)有專門(mén)的前端的,都是其他方向轉(zhuǎn)行來(lái)的)
- class 是保留字腮鞍,遲早要實(shí)現(xiàn) class
- 大部分人對(duì)原型的理解不夠(因?yàn)榇蠖鄶?shù)都語(yǔ)言是使用 class 來(lái)描述面向?qū)ο螅?/li>
語(yǔ)法
// 寫(xiě)法一
class PointClass {
x: number = 0
y: number = 0
}
// 寫(xiě)法二
class PointClass {
x: number
y: number
constructor() {
this.x = 0
this.y = 0
}
}
// 寫(xiě)法三
class PointClass {
x!: number // 這里必須斷言,因?yàn)槌跏蓟辉?constructor 的明面上
y!: number
constructor() {
this.xxx()
}
xxx() {
this.x = 0
this.y = 0
}
}
來(lái)看一組對(duì)比:
interface PointInterface {
x: number;
y: number;
}
// TODO: 注意:下面這個(gè)示例在 JS 中可以的莹菱,在 TS 中會(huì)報(bào)錯(cuò)
class PointClass {
x: number;
y: number;
}
看起來(lái)很像是吧~
interface 只有成員的類型沒(méi)有實(shí)現(xiàn)
class 須同時(shí)有成員的類型和實(shí)現(xiàn)
其實(shí)這個(gè)才是我最喜歡的寫(xiě)法:
class Point {
constructor(public x: number = 0, public y: number = 0) {
}
}
函數(shù)重載
class Point {
x!: number;
y!: number;
constructor(x: number, y: number);
constructor(s: string);
constructor(xs: number | string, y?: number) {
if (typeof xs === 'number' && typeof y === 'number') {
this.x = xs
this.y = y
} else if (typeof === 'string') {
const parts = xs.split(',')
this.x = parseFloat(parts[0])
this.y = parseFloat(parts[1])
}
}
}
看起來(lái)有點(diǎn)復(fù)雜把~
class 可以實(shí)現(xiàn)接口
使用 implements
interface Person {
name: string;
sayHi: (target: Person) => void
}
class User implements Person {
constructor(public name: string) {}
sayHi(target: Person) {
console.log(`Hi ${target.name}`)
}
}
實(shí)現(xiàn)是什么意思移国?就是你有的我都有,那這個(gè)不是和繼承差不多嘛
確實(shí)差不多道伟,但是你“繼承”一個(gè)接口迹缀,就叫做實(shí)現(xiàn)。接口繼承接口蜜徽,類繼承類祝懂,那才叫做繼承
面向?qū)ο髮?duì)就喜歡整這些有的沒(méi)的的概念
實(shí)現(xiàn)兩個(gè)接口
interface Person {
name: string;
sayHi: (target: Person) => void
}
interface Tag {
tag: string[];
}
class User implements Person, interface {
tag: string[] = []
constructor(public name: string) {
this.name = '1'
}
sayHi(target: Person) {
console.log(`Hi ${target.name}`)
}
}
思考:來(lái)看一個(gè)問(wèn)題
interface Person {
name: string;
age?: number;
sayHi: (target: Person) => void
}
class User implements Person {
constructor(public name: string) {}
sayHi(target: Person) {
console.log(`Hi ${target.name}`)
}
}
const u = new User('jack')
u.age // TODO: 這里會(huì)出現(xiàn)什么樣的結(jié)果
問(wèn):u.age 的值是多少?
- 0
- undefined
- typescript 報(bào)錯(cuò)
很顯然是報(bào)錯(cuò)拘鞋,
Person 是一個(gè)接口啊砚蓬,又不會(huì)幫你實(shí)現(xiàn),你的 User 也沒(méi)有實(shí)現(xiàn) age盆色,所以是報(bào)錯(cuò)
class 可以繼承 class
class Person {
constructor(public name: string) {}
sayHi() {
console.log(`Hi ${thyis.name}`)
}
}
class User extends Person {
constructor(public id: number, name: string) {
super(name)
}
login() {}
sayHi(target?: User) { // TODO: 注意:這叫做重寫(xiě)
if (target === undefined) {
supper.sayHi()
} else {
console.log(`你好灰蛙,${target.name}祟剔, 我是${this.name}`)
}
}
}
注意這里需要調(diào)用 super
為什么是這個(gè)單詞?因?yàn)槊嫦驅(qū)ο笏謥?lái)了摩梧,
通常我們都說(shuō)父類和子類物延,而偏偏面向?qū)ο笠凶?strong>超類,就是喜歡發(fā)明概念
關(guān)于重寫(xiě)的一個(gè)思考
再來(lái)看一個(gè)栗子
class Person {
friend?: Person
constructor(public name: string, friend?: Person) {
this.friend = friend
}
}
class User extends Person {
constructor(public id: number, name: string, friend?: User) {
super(name, friend)
}
login() {}
sayHi(target?: User) { // TODO: 注意:這叫做重寫(xiě)
if (target === undefined) {
supper.sayHi()
} else {
console.log(`你好障本,${target.name}教届, 我是${this.name}`)
}
}
}
const u1 = new User(1, 'jack')
const u2 = new User(1, 'jack2', u1)
u2.friend // TODO: 請(qǐng)問(wèn)這里的類型是什么
請(qǐng)問(wèn)這里的 u2.friend
類型是什么?
直接看答案:
很奇怪把驾霜,明明傳進(jìn)去的 u1案训,類型是 User,怎么顯示出來(lái)是 Person粪糙?强霎!
可能是因?yàn)槲覀冊(cè)?User 的時(shí)候并沒(méi)有實(shí)現(xiàn) friend,friend 是在 Person 實(shí)現(xiàn)的蓉冈,自然會(huì)用 Person 里的 friend 的類型
所以我們要怎么做呢城舞?用類型重寫(xiě)
class Person {
friend?: Person
constructor(public name: string, friend?: Person) {
this.friend = friend
}
}
class User extends Person {
declare friend?: User // TODO: 注意這里:需要使用 declare
constructor(public id: number, name: string, friend?: User) {
super(name, friend)
}
login() {}
sayHi(target?: User) { // TODO: 注意:這叫做重寫(xiě)
if (target === undefined) {
supper.sayHi()
} else {
console.log(`你好,${target.name}寞酿, 我是${this.name}`)
}
}
}
好家夺,面向?qū)ο笥謥?lái)事了,
想直接覆蓋伐弹?不可以拉馋,只能用我提供的關(guān)鍵詞 declare 來(lái)覆蓋
最后再來(lái)思考一個(gè)問(wèn)題
這里的 friend 是 User 的還是 Person 的?
其實(shí)這個(gè)問(wèn)題沒(méi)必要糾結(jié)惨好,之所以問(wèn)出這個(gè)問(wèn)題是因?yàn)槟闵钍茉玩湹挠绊?/p>
原型鏈和 class 是兩個(gè)不同的流派煌茴,沒(méi)人會(huì)關(guān)心你這個(gè)東西是在哪里實(shí)現(xiàn)的,沒(méi)人會(huì)關(guān)心你這個(gè)是獨(dú)有屬性日川,還是共有屬性蔓腐,只要給你實(shí)現(xiàn)出來(lái)就行了
最后提醒一點(diǎn),如果你在學(xué)習(xí)另一門(mén)語(yǔ)言龄句,在你沒(méi)學(xué)會(huì)之前回论,千萬(wàn)不要把這兩個(gè)語(yǔ)言進(jìn)行對(duì)比炎咖,這樣只會(huì)搞的更混亂