成員可見(jiàn)性
- public 類(lèi)外可見(jiàn)
- private 類(lèi)內(nèi)可見(jiàn) #var 真私有屬性
- protected 子類(lèi)和自己可見(jiàn)
// public
class Person1 {
public friend?: Person
constructor(public name: string, friend?: Person) {
this.friend = friend
}
}
const p1 = new Person1('jack')
p1.friend // undefined
// private
class Person2 {
private friend?: Person
constructor(public name: string, friend?: Person) {
this.friend = friend
}
xxx() {
this. friend // TODO: 這里是可以使用的
}
}
const p2 = new Person2('jack', p1)
p2.friend // TODO: typescript 報(bào)錯(cuò)
// protected
class Person3 {
private friend?: Person
constructor(public name: string, friend?: Person) {
this.friend = friend
}
xxx() {
this. friend // TODO: 這里是可以使用的
}
}
class User extends Person3 {
constructor(public id: number, name: string, friend?: User) {
super(name, friend)
}
yyy() {
this.friend // TODO: 子類(lèi)這里是可以使用的
}
}
const u = new User(1, 'jack')
u.friend // TODO: typescript 報(bào)錯(cuò)
但是這些代碼始終都會(huì)變成 JS
那么說(shuō),TS 提供的這三個(gè)關(guān)鍵詞還有用嘛?
顯然易見(jiàn):因?yàn)轭?lèi)型擦除,在 JS 中,你又可以隨心所欲了
但是我就想要私有屬性怎么辦,那就使用 JS 的#
class Person {
#friend?: Person
constructor(public name: string, friend?: Person) {
this.#friend = friend
}
}
const p = new Person('jack')
p.friend // TODO: typescript 報(bào)錯(cuò)
static
static 的意思是這個(gè)屬性是通過(guò)類(lèi)名訪(fǎng)問(wèn)的
class Person {
xxx = 1
name: string
constructor(name: string) {
this.name = name
}
}
Person.xxx // TODO: typescript 報(bào)錯(cuò)
所以為了解決上面的問(wèn)題,面向?qū)ο笥旨恿艘粋€(gè)關(guān)鍵字,static
class Person {
static xxx = 1
name: string
constructor(name: string) {
this.name = name
}
}
Person.xxx // TODO: 可以使用了
這就叫做靜態(tài)屬性
這里在提示一下 name 叫做成員屬性
什么區(qū)別?靜態(tài)屬性是代碼執(zhí)行到哪一行的時(shí)候就初始化了,而成員屬性是實(shí)例化后才初始化的
但是使用 staic 的時(shí)候需要注意一點(diǎn)
他不能在固有屬性上使用
class Person {
static name: string // TODO: 報(bào)錯(cuò)啦
name: stirng
constructor(name: string) {
this.name = name
}
}

為什么會(huì)這樣呢?
這又要追尋到 JS 的問(wèn)題了:JS 中的 class 是用函數(shù)實(shí)現(xiàn)的
怎么證明,用 typeof:
class 是個(gè) function,且自然自帶 name,這樣看來(lái),JS 中的 class 就是辣雞,看起來(lái)實(shí)現(xiàn)了 class,但又好像是個(gè)殘廢,所以有關(guān)固有屬性的都會(huì)報(bào)錯(cuò)
class Person {
static length: string // TODO: 報(bào)錯(cuò)啦
static prototype: string // TODO: 報(bào)錯(cuò)啦
static arguments: string // TODO: 報(bào)錯(cuò)啦
static caller: string // TODO: 報(bào)錯(cuò)啦
name: stirng
constructor(name: string) {
this.name = name
}
}
static block
需求是這樣:我們想記錄這個(gè)功能被創(chuàng)建過(guò)多少次?
如果是 JS 程序員,那么很簡(jiǎn)單
let count = parseInt(loocalStorage.getItem('count') || 0)
count += 1
如果是在 class 里面那就很難做到,除非~再加個(gè)語(yǔ)法
class Foo {
static #count = 0
static { // TODO: 注意這里,這種語(yǔ)法代表類(lèi)在創(chuàng)建的時(shí)候會(huì)執(zhí)行
const count = loadFrimLocalStorage() || 0
Foo.#count += count
}
constructor() {
console.log(Foo.#count)
}
}
類(lèi)和泛型
class Hash<K, V> {
map: Map<K, V> = new Map()
set(key: K, value: V) {
this.map.set(key, value)
}
get(key: K) {
return this.map.get(key)
}
}
const h = new Hash<string | number, string | number>()
h.set('name', 'hi')
g.get('name')
其實(shí)上面這個(gè) Hash 就是一個(gè) Map,那么直接用繼承就好了
class Hash<K, V> extends Map<K, V> {
destory() {
this.clear()
}
}
抽象類(lèi)
interface A {}
class B {}
interface 只能寫(xiě)類(lèi)型,不寫(xiě)實(shí)現(xiàn)
class 又寫(xiě)類(lèi)型,又寫(xiě)實(shí)現(xiàn)
人都喜歡折中
能不能有的實(shí)現(xiàn),有的不實(shí)現(xiàn)呢?
為了應(yīng)對(duì)這個(gè)需求,又來(lái)到了面向?qū)ο笫煜さ牟僮鳎?strong>加關(guān)鍵字, abstract
abstract class Person {
a() {
console.log('a')
}
abstract name: string
abstract b: () => number
}
這就是抽象類(lèi),請(qǐng)注意這個(gè)抽象類(lèi)是不能直接使用的!
const p = new Person()
// TODO: 報(bào)錯(cuò):Cannot Create an Instance of an abstract class.ts
把類(lèi)當(dāng)作參數(shù)(常用)
把類(lèi)作為參數(shù),而不是把對(duì)象作為參數(shù)
class Person {}
function fn(X: Person) { // TODO: typescript 報(bào)錯(cuò)
const p = new X()
}
fn(Person)
怎么解決呢?下面兩種方式
// 第一種:
function fn1(X: typeof Person) {
const p = new X()
}
// 第二種:
function fn2(X: new (name: string) => Person) {
const p = new X()
}
看起來(lái)很奇怪把~
個(gè)人對(duì) class 的看法
有這么多關(guān)鍵字,有這么多語(yǔ)法,搞的像背書(shū)一樣,每個(gè)關(guān)鍵字是什么意思,怎么組合,該怎么聲明類(lèi)型,全都是固定的,都是套路,都是模版,有什么好處呢?
那就是工業(yè)化,千人一面,大家寫(xiě)出來(lái)的代碼都是一樣的,即使你是新手,你也能看懂老手的代碼,大家溝通起來(lái)就簡(jiǎn)單多了。
如果說(shuō)面向?qū)ο筮m合前端就罷了,但是實(shí)際上來(lái)看,雖然以前轉(zhuǎn)向前端的都是面向隨想那幫人,他們自然而然在寫(xiě)前端時(shí)候會(huì)加入各種組合,各種設(shè)計(jì)模式,
但是從 ES6 開(kāi)始,前端就希望代碼更加簡(jiǎn)化,希望更多的函數(shù)和對(duì)象組合,雖然這個(gè)時(shí)候出了真正的關(guān)鍵詞 class,但是很多前端就是不用,你 class 的功能我全都可以用函數(shù)和對(duì)象來(lái)實(shí)現(xiàn),直到今年 react 和 vue 都出了 hooks API,他們連 this 都不用了,更不用說(shuō) new 了,所以事實(shí)證明,不用 class 也能寫(xiě)出很好的程序。
