01
給類定義屬性
class Point {
// x: number = 2
// y: number = 4
x: number
y: number
constructor() {
this.x = 2222
this.y = 22255
}
}
const pt = new Point()
pt.x = 33
pt.y = 22
//也可以斷言
class OKG{
name!:string
}
02
class Greater {
readonly name: string = 'world'
constructor() {
this.name = 'hello'
}
}
const G = new Greater()
//G.name = 'g' //報(bào)錯(cuò)份殿,無法分配到name膜钓,因?yàn)樗侵蛔x屬性
//constructor() 是再new的時(shí)候運(yùn)行的,可以傳入?yún)?shù),定義參數(shù)類型等
class Greater2 {
readonly name: string = 'world'
constructor(other?: string) {
if (other !== undefined) {
this.name = other
}
}
}
const g = new Greater2('hello')
console.log(g.name);
03
構(gòu)造函數(shù)-constructor卿嘲∷绦保可以定義參數(shù),傳初始值拾枣,然后再重新賦值即可
class P {
x: string;
z: number
constructor(x: string='', z: number=0) {
this.x = x;
this.z = z
}
}
const t = new P()
console.log(t.z);
console.log(t.x);
//注意:構(gòu)造函數(shù)不能有類型參數(shù)沃疮,構(gòu)造函數(shù)不能有返回類型注釋
04
類里面的函數(shù),我們稱之為方法
class Int {
x: number;
z: number
constructor(x: number = 2, z: number = 0) {
this.x = x;
this.z = z
}
add(sum: number) {
let y = this.z + this.x
let su = sum + y
console.log(y);
console.log(su);
}
}
const pg = new Int()
pg.x = 4
pg.z = 5
pg.add(3)//傳實(shí)參
05
Getters/Setters
如果存在get,但沒有set屬性梅肤,則改屬性自動(dòng)是可讀的
如果沒有指定setter參數(shù)的類型司蔬,它將從getter返回類型中推斷出來
//訪問器和設(shè)置器必須有相同的成員可見性 get和set的函數(shù)方法名相同
class C {
_length = 9;
get length() {
return this._length;
}
set length(value) {
this._length = value
}
}
const cl = new C()
console.log(cl.length);// 9
06
類
class MyClass {
[s: string]: boolean | ((s: string) => boolean)
x = true
check(s: string) {
return this[s] as boolean //斷言
}
}
07
interface Pingable {
ping(): void;
}
class SO implements Pingable {
ping(): void {
console.log("ping!");
}
}
let so: SO = new SO()
so.ping()
interface A{
x:number;
y?:number
}
class C2 implements A{
x=99
}
const cll=new C2()
console.log(cll.x);//99
//console.log(cll.y);//undefined,C2上不存在屬性y
08
class Animal {
dog: string
constructor(dog: string = '') {
this.dog = dog
}
}
class Dog extends Animal {
pick: string
constructor(pick: string = '') {
super()
this.pick = pick
}
}
const zoo = new Dog()
console.log(zoo.dog = 'yellow');
console.log(zoo.pick = 'pink');
09
重寫方法(基類和派生類)
//基類
class Base {
greet() {
console.log('hello lady');
}
}
//派生類
class Derived extends Base {
greet(name?: string): void {
if (name === undefined) {
super.greet()
} else {
console.log(name.toUpperCase());//toUpperCase()將傳入的string轉(zhuǎn)換為大寫
}
}
}
const d = new Derived()
d.greet()
d.greet('reader')
//注意:派生類要遵循基類的契約,契約就是凭语,如Derived類覆蓋Base類葱她,一定要與Base兼容,比如這里傳入的參數(shù)似扔,如果name為必傳參數(shù)那么就會(huì)報(bào)錯(cuò)吨些,類型不匹配
const b:Base =d
b.greet()
10
基類和派生類初始化的順序
1.基類的字段被初始化
2.基類構(gòu)造函數(shù)運(yùn)行
3.派生類的字段被初始化
4.派生類構(gòu)造函數(shù)運(yùn)行
class Basic {
name = "base";
constructor() {
console.log("my name is" + " " + this.name);
}
}
class Deri extends Basic {
name = "derived";
}
const dd = new Deri();
//優(yōu)先初始化 基類的初始值
11
繼承內(nèi)置類型,什么是內(nèi)置類型呢炒辉?比如array豪墅,error,map等等黔寇,這些TS內(nèi)置的一些對(duì)象.
//例:
class MsgError extends Error{
constructor(m:string){
super(m)
// //es5及以下偶器,可以明確地設(shè)置原型
// Object.setPrototypeOf(this,MsgError.prototype)
}
sayHello(){
return 'hello ' + this.message
}
}
const msgError=new MsgError('lady')
console.log(msgError.sayHello()); //hello lady
//這里的定義了一個(gè)類叫MsgError,它繼承了Error這個(gè)內(nèi)置的對(duì)象,Error就是內(nèi)置的一個(gè)類或者一個(gè)對(duì)象缝裤,有時(shí)候我們?cè)诜治鰞?nèi)置類型的結(jié)構(gòu)的時(shí)候屏轰,可能出乎我們的意料,這個(gè)呢憋飞,主要表現(xiàn)在我們編譯的時(shí)候使用的是什么target霎苗,比如我們使用ES6以上的版本,我們可能不用關(guān)心太多的關(guān)于繼承內(nèi)置類型的一些問題榛做,如果是ES5及以下的版本的話唁盏,就需要注意了
12
class A{
constructor(){
}
public add(){
}
protected pro(){
}
private pri(){
}
}
const a:A=new A()
a.add()
13
類里的static區(qū)塊
static 靜態(tài)成員和static # 靜態(tài)的區(qū)別,最大的區(qū)別是:帶#號(hào)的就變成了私有的這樣的屬性检眯,比如說我們可以在類的內(nèi)部通過getter來去訪問厘擂,但訪問的時(shí)候呢,我們?nèi)耘f是可以通過類名去訪問它锰瘸,同時(shí)我們?cè)陬惱镞€可以寫一個(gè)static這樣的塊刽严,這個(gè)static后面可以直接跟這個(gè)大括號(hào){},然后我們可以通過類名訪問我們當(dāng)前類里邊的通過#號(hào)來定義的這些靜態(tài)的屬性获茬,那我們?cè)陬惖耐膺呍噲D去訪問一下這個(gè)#count 是行不通的港庄,也就是說它是私有的
class Foo {
static #count = 0;
get count() {
return Foo.#count;
}
static {
try {
const lastInstances = {
length: 100
}
Foo.#count += lastInstances.length;
}
catch{
//....
}
}
}
// Foo.#count //報(bào)錯(cuò)倔既,屬性#count在類FOO外部不可訪問,因?yàn)樗哂袑S脴?biāo)識(shí)符
14
泛型類
class Box<Type>{
contents:Type
constructor(value:Type){
this.contents=value
}
// static defaultValue:Type//報(bào)錯(cuò):靜態(tài)成員不能引用類類型參數(shù)
}
const box:Box<string>=new Box('bunny')
15
類運(yùn)行時(shí)的this
class Myclass {
name = "Myclass";
// getName() {
// return this.name
// }
// //(1)箭頭函數(shù)
// getName=()=> {
// return this.name
// }
//(2)this參數(shù)
getName(this:Myclass) {
return this.name
}
}
const c = new Myclass()
console.log(c.getName());//Myclass
const obj = {
name: "obj",
getName: c.getName
}
// console.log(obj.getName()); //obj
//得到的name是const下的name鹏氧,而不是我們初始化指向this下的name渤涌。解決方法:(1)箭頭函數(shù)。(2)this參數(shù)
//(1)使用箭頭函數(shù)后得到的是Myclass
//console.log(obj.getName()); //Myclass
//(2)使用this參數(shù)后得到的是obj .就是說把还,誰調(diào)的我我就打印誰
console.log(obj.getName()); //obj
總結(jié):
為了保證我們類里邊的某個(gè)函數(shù)的this指向实蓬,沒有問題,我們可以采用箭頭函數(shù)和this參數(shù)兩種方法吊履,使用的時(shí)候一定要權(quán)衡安皱,this這個(gè)值保證在運(yùn)行的時(shí)候是正確的,即使我們沒有經(jīng)過TS檢查代碼也是如此艇炎。第二呢酌伊,使用箭頭函數(shù),它會(huì)使用更多的內(nèi)存缀踪,因?yàn)槊總€(gè)類實(shí)例將有它自己的副本每個(gè)函數(shù)都是這樣定義的居砖,第三個(gè)呢,使用箭頭函數(shù)不能在派生類中使用super.getName驴娃,也就是我們不能在子類里邊通過super來調(diào)父類這個(gè)方法了奏候,因?yàn)樵谠玩溨袥]有入口可以獲得基類的方法,那如果是我們使用this參數(shù)這種方式來解決這個(gè)問題唇敞,它也有一些取舍的地方蔗草,首先呢,javascripe調(diào)用者仍然可能在不知不覺的錯(cuò)誤中來用類的方法疆柔,比方說剛才我們最后的這個(gè)調(diào)用咒精,另外呢,每個(gè)類只有一個(gè)函數(shù)被分配旷档,而不是每個(gè)實(shí)例會(huì)創(chuàng)建一個(gè)函數(shù)狠轻,另外呢,基類方法這個(gè)定義仍然可以通過super來調(diào)用彬犯,這個(gè)要優(yōu)于剛才我們說的箭頭函數(shù),所以采用哪種方法取決于我們正常的業(yè)務(wù)需求即可
16
class Boxes {
contents: string = "";
set(value: string) {
this.contents = value
// console.log(this);//Boxes { contents: 'hello' }
return this;
}
}
class ClearableBoxes extends Boxes {
clear() {
this.contents = ''
}
}
const boxes = new Boxes()
const bo = boxes.set('bunny')
console.log(bo);//此時(shí)this返回的是 Boxes { contents: 'bunny' }
// boxes.set('hello')
const boxes1 = new ClearableBoxes()
const bo1 = boxes1.set('bunny')
console.log(bo1);//此時(shí)this返回的是 ClearableBoxes { contents: 'bunny' }
17
//基于類型守衛(wèi)的this
//this is Type
class ValueBox<T>{
value?: T
hasValue(): this is { value: T } {
return this.value !== undefined
}
}
const valueBox = new ValueBox()
valueBox.value = 'bunny'
if (valueBox.hasValue()) {
console.log(valueBox.value);//bunny
}
18
class Params {
constructor(public readonly x: number = 9, y: number = 99, private a: string = 'bunny') {
//...
}
}
const p = new Params()
//類表達(dá)式
const someClass = class <Type>{
content: Type
constructor(value: Type) {
this.content = value
}
}
const m = new someClass('bunny')
console.log(m.content)
19
abstract class AbstractBase{
abstract getName():string
printName(){
console.log(this.getName());
}
}
//const abst=new AbstractBase()//報(bào)錯(cuò)查吊,無法創(chuàng)建抽象類的實(shí)例
//想要調(diào)用抽象類的函數(shù)要再聲明一個(gè)類來繼承抽象類
class ExtAbstract extends AbstractBase{
getName(): string {
return 'bunny'
}
}
const abstract=new ExtAbstract()
abstract.getName()
abstract.printName()
20
class Xx {
x: number = 2
y: number = 3
}
class Yy {
x: number = 24
y: number = 34
}
const xy: Xx = new Yy()
let x1 = xy.x = 88
console.log(x1);