typescript中的类和es5中的类
es5中定义一个类
简单的类
//最简单的类
function People(){ this.name="张三", this.age=20 } var p=new People(); console.log(p.name)
构造函数和原型链里面增加方法
//构造函数和原型链里面增加方法 function People(){ this.name="张三", //属性 this.age=20, this.fun=function(){ console.log(this.age) } }
//原型链的属性会被多个实例共享,构造函数中的不会 People.prototype.work=function(){ console.log(this.name+"在学习") } var p=new People(); p.fun() p.work()
类中的静态方法
//类中的静态方法 function People(){ this.name="张三", //属性 this.age=20, this.fun=function(){ //实例方法 console.log(this.age) } } People.getInfo=function(){ //不需要实例化,直接通过类.方法调用 console.log("我是静态方法") } People.getInfo()
es5中的继承
对象冒充实现继承
// es5中的继承 function People(){ this.name="张三", //属性 this.age=20, this.fun=function(){ //实例方法 console.log(this.age) } } People.prototype.work=function(){ console.log(this.name+"在学习") } //web类,继承People类 , 原型链+对象冒充的组合继承模式 function Web(){ //对象冒充实现继承 People.call(this) } var w =new Web(); w.fun() //对象冒充可以继承构造函数里面的属性和方法
但是如果要调用work方法就会报错
注意:对象冒充可以继承函数里面的属性和方法,但是没法继承原型链中的属性和方法
原型链继承
function People(){ this.name="张三", //属性 this.age=20, this.fun=function(){ //实例方法 console.log(this.age) } } People.prototype.work=function(){ console.log(this.name+"在学习") } //web类,继承People类 , 原型链+对象冒充的组合继承模式 function Web(){ } //原型链继承 Web.prototype=new People(); var w =new Web(); w.fun() //对象冒充可以继承构造函数里面的属性和方法 w.work()
原型链继承既可以继承构造函数中的属性和方法,也可以继承原型链中的属性和方法
原型链继承中的问题
首先我们看下面的案例
//原型链继承中的问题 function People(name,age){ this.name=name, //属性 this.age=age, this.fun=function(){ //实例方法 console.log(this.name) } } People.prototype.work=function(){ console.log(this.name+"在学习") } //web类,继承People类 , 原型链+对象冒充的组合继承模式 function Web(name,age){ } //问题出现了 Web.prototype=new People(); var w=new Web("赵四",18) var w1=new Web("王五",13) w.fun()
此时运行我们可以看输出为undefined
这是因为实例化子类的时候没法给父类传参
原型链+构造函数的组合继承模式
//原型链+构造函数的组合继承模式 function People(name,age){ this.name=name, //属性 this.age=age, this.fun=function(){ //实例方法 console.log(this.name) } } People.prototype.work=function(){ console.log(this.name+"在学习") } //web类,继承People类 , 原型链+对象冒充的组合继承模式 function Web(name,age){ People.call(this,name,age) //对象冒充继承,实例化子类可以给父类传参 } //问题出现了 Web.prototype=new People(); var w=new Web("赵四",18) //实例化子类的时候没法给父类传参 w.fun()
原型链+构造函数的组合继承模式l另一种方法
//原型链+构造函数的组合继承模式l另一种方法 function People(name,age){ this.name=name, //属性 this.age=age, this.fun=function(){ //实例方法 console.log(this.name) } } People.prototype.work=function(){ console.log(this.name+"在学习") } //web类,继承People类 , 原型链+对象冒充的组合继承模式 function Web(name,age){ People.call(this,name,age) //对象冒充继承,可以继承构造函数里面的属性和方法,实例化子类可以给父类传参 } //问题出现了 Web.prototype= People.prototype; var w=new Web("赵四",18) //实例化子类的时候没法给父类传参 w.fun()
ts中类的定义
我们接下来看在ts中类的使用
// ts中类的定义 class Person{ name:string; //属性,前面省略的public关键词 constructor(n:string){ //构造函数,实例化类的时候触发的方法 this.name=n; } fun():void{ console.log(this.name) } } var p=new Person("小明"); p.fun()
我们看一下编译之后的js文件
我们再来看一下ts中的set和get方法
class Person{ name:string; //属性,前面省略的public关键词 constructor(name:string){ //构造函数,实例化类的时候触发的方法 this.name=name; } getName():string{ return this.name } setName(name:string):void{ this.name=name } } var p=new Person("小明"); console.log(p.getName()) p.setName("小红") console.log(p.getName());
我们看一下编译之后的js文件
ts中的继承
在ts中通过extends和super实现继承
//ts中实现继承 extends super class Person{ name:string; constructor(name:string){ this.name=name } fun():string{ return `${this.name}在写作业` } } var p= new Person("小明"); console.log(p.fun())
编译后的js文件
ts继承:父类方法和子类方法一致
class Person{ name:string; constructor(name:string){ this.name=name } fun():string{ return `${this.name}在写作业` } } class Web extends Person{ constructor(name:string){ super(name) //初始化父类的构造函数
} } var w=new Web("李四") console.log(w.fun())
编译后的js文件
ts继承:父类方法和子类方法不一致
我们在Web类中添加一个方法然后再调用
class Web extends Person{ constructor(name:string){ super(name) //初始化父类的构造函数 } work(){ console.log(`${this.name}学习`) } }
编译后的js文件
如果我们子类中也有一个方法跟父类中的方法一样
fun():string{ return `${this.name}在打游戏` }
我们看一下输出结果
父类和子类有同样的方法的时候,调用子类的方法时,首先在子类中找,如果子类中没有在去父类中找
ts类中的修饰符
ts中定义属性的时候提供了三种修饰符:
- public:公有,(在类里面,子类,类外面都可以访问)
- protected:保护类型,(在类里面,子类可以访问,在类外面没法访问)
- private:私有,(在类里面可以访问,子类和类外面没法访问)
属性如果不加修饰符默认为public
1.public
我们看下面的案例
public:公有,(在类里面,子类,类外面都可以访问)
class Person{ public name:string; //公有属性 constructor(name:string){ this.name=name } fun():string{ return `${this.name}在写作业` } } class Web extends Person{ constructor(name:string){ super(name) //初始化父类的构造函数 } work(){ console.log(`${this.name}学习`) } fun():string{ return `${this.name}在打游戏` } } var w=new Web("李四") w.work() //类外部访问公有属性 var p=new Person("老王") console.log(p.name)
我们可以看到属性如果为public,那么在类中,子类,类外面都可以访问这个属性
2.protected
//protected:保护类型,(在类里面,子类可以访问,在类外面没法访问) class Person{ protected name:string; //公有属性 constructor(name:string){ this.name=name } fun():string{ return `${this.name}在写作业` } } class Web extends Person{ constructor(name:string){ super(name) //初始化父类的构造函数 } work(){ console.log(`${this.name}学习`) } } var w=new Web("李四") w.work() console.log(w.fun())
此时我们可以看到在子类中可以正常访问
但是当我们在外部访问属性时:
//类外部访问公有属性 var p=new Person("老王") console.log(p.name)
我们看一下编译后的js文件
此时ts编译会报错,但是浏览器会输出结果,这是因为把tsclass语法转义成了js,所以能够运行
3.private
//private:私有,(在类里面可以访问,子类和类外面没法访问) class Person{ private name:string; //公有属性 constructor(name:string){ this.name=name } fun():string{ return `${this.name}在写作业` } } class Web extends Person{ constructor(name:string){ super(name) //初始化父类的构造函数 } work(){ console.log(`${this.name}学习`) } } var p=new Person("李四") console.log(p.fun()) var w=new Web("李四") w.work() console.log(w.work())
此时我们在终端可以看到报错,不论在子类中使用,还是在外类中使用都会报错
此时我们在类中使用
//private:私有,(在类里面可以访问,子类和类外面没法访问) class Person{ private name:string; //公有属性 constructor(name:string){ this.name=name } fun():string{ return `${this.name}在写作业` } } class Web extends Person{ constructor(name:string){ super(name) //初始化父类的构造函数 } } var p=new Person("李四") console.log(p.fun())
此时不会报错,可以看到浏览器输出
ts中的静态属性和静态方法
class Person{ name:string constructor(name:string){ this.name=name } fun(){ //实例方法 console.log(`${this.name}在学习`) } work(){ //实例方法 console.log(`${this.name}在工作`) } static play(){ //在方法的前面加上一个static即为静态方法 console.log("静态方法") } } //实例化调用实例方法 var p=new Person("小明") p.fun(); //静态方法调用 Person.play()
编译后的ejs文件
但是静态方法不能直接调用类中的属性
此时我们在静态方法中输出age属性
public age:string=20 ...... static play(){ console.log("静态方法",this.age) }
结果返回的结果是undefined
如果我们想要获取这个属性
就需要把这个属性改为静态属性,在属性名前加上static关键字
static age:number=20
static play(){ console.log("静态方法",Person.age) console.log("静态方法",this.age) }
这两种方法都可以获取静态属性
多态
父类定义一个方法不去实现,让继承他的子类去实现,每一个子类有不同的表现
多态也是继承的一种表现,
class Animal{ name:string; constructor(name:string){ this.name=name; } eat(){ //具体吃什么不知道 具体吃什么,让继承的子类实现,每一个类的表现不一样 console.log("吃的方法") } } class Dog extends Animal{ constructor(name:string){ super(name); } eat(){ console.log( this.name+"吃肉") } } class Cat extends Animal{ constructor(name:string){ super(name); } eat(){ console.log( this.name+"老鼠") } } var dog= new Dog("大黄") dog.eat() var cat= new Cat("橘猫") cat.eat()
我们看一下编译之后的js文件
抽象方法
ts中的抽象类,它是由其他类继承的基类,不能直接被实例化
用abstract关键字定义的抽象类的和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
abstract抽象方法只能放在抽象类里面
抽象类和抽象方法用来定义标准,标准就是Animal这个类要求他的子类必须包含eat方法
我们看下面的代码
abstract class Animal{ abstract eat():any; } var a =new Animal()
抽象方法放在抽象类中
但是不能实例化这个类
此时就会报错
案例:
abstract class Animal{ name:string; constructor(name:string){ this.name=name } abstract eat():any; } class Dog extends Animal{ constructor(name:string){ super(name); } //抽象类的子类必须实现抽象类中的方法 eat(){ console.log(`${this.name}吃肉`) } } var d=new Dog("大黄") d.eat()
编译后的js文件
此时我们在定义一个Cat类,继承Animal类但不会实现Animal中的eat方法
class Cat extends Animal{ constructor(name:string){ super(name); } fun(){ console.log(`${this.name}吃肉`) } }
此时就会报错
如果继承抽象类,就必须实现抽象父类中的方法