传统的javascript只有对象,没有类的概念,对于面向对象方式编程没有很好的设计,当发现问题时,已经成千上万的人在使用了,所以大的修改几乎没有,都是各种修修补补,小的语法糖更新,例如es6新加入的类Class,当然class并不是语法糖,但核心还是围绕prototype来玩。
这里先放一个es5定义一个类
function Cat(name){
this.name = name;
this.say = function(){console.log(this.name)}
}
var cat1 = new Cat('dahuang')
cat1.say();
//可以dir看一下方法还是在_proto_上的
使用 class定义一个类
class Cat{
constructor(name){
this.name = name;
}
say(){ console.log(this.name) }
}
var cat1 = new Cat('dahuang')
cat1.say();
换汤不换药,看起来反正是舒服些了,下面是ts中类的定义
class Cat {
name: string;//属性
constructor(name: string) {//构造函数 实例化触发
this.name = name;
}
say():void{//方法
console.log(this.name)
}
}
var cat1 = new Cat('dahuang')
cat1.say();
执行的顺序是new一个构造了一个cat实例,调用cat类中的构造函数,把传入的dahuang赋值给属性;
继承方面和es6的class的继承也基本一致,通过extends\super
class Cat {
name: string;//属性
constructor(name: string) {//构造函数 实例化触发
this.name = name;
}
say(): void {//方法
console.log(this.name)
}
}
class Dog extends Cat{}
let dog = new Dog('mimi');
dog.say()
//mimi
这个例子展示了最基本的继承,Dog是一个派生类,它派生自 Cat基类,通过 extends关键字。派生类通常被称作子类,基类通常被称作超类。派生类从基类中继承了属性和方法。突然这个傻狗有了自己的想法,事情就不那么简单了
class Cat {
name: string;
constructor(name: string) {
this.name = name;
};
say(): void {
console.log(this.name)
}
}
class Dog extends Cat{
dosth:string
constructor(dosth: string){
this.dosth = dosth
};
}
这段甚至都不需要编译,在写的时候编辑器就一大票中国红了,并且提示我们派生类的构造函数必须包含super
class Cat {
name: string;
constructor(name: string) {
this.name = name;
};
say(): void {
console.log(this.name)
}
}
class Dog extends Cat{
dosth:string
constructor(name:string,dosth: string){
super(name)
this.dosth = dosth
};
justdoit():void{
console.log(this.dosth)
}
}
let dog = new Dog('mimi', '撒野尿')
dog.say() //mimi
dog.justdoit() //撒野尿
这次按照提示加入了super关键字,mimi顺利的完成了它的壮举,可以说这里的super()就是代表了基类的构造函数;
ts定义属性的时候提供了三种修饰符,分别是
公共的public
受保护的protected
私有的provite
默认为public,表示在类里面、派生类、类以外都可以访问;
在上面的例子里,我们可以自由的访问cat里的属性,ts成员都默认为 public,写全就是
class Cat {
public name: string;
constructor(name: string) {
this.name = name;
};
say(){console.log(this.name)}
}
class cat1 extends Cat();
let cat = new Cat('xiaobai')
let cat1 = new Cat('dahuang')
cat.name;
cat.say();
cat1.name;
cat1.say();
//内外子类中都可以访问到
在类里面可以进行访问,派生类、类以外都无法访问;
class Cat {
public name: string;
constructor(name: string) {
this.name = name;
};
say(){console.log(this.name)}
}
class cat1 extends Cat();
let cat = new Cat('xiaobai')
let cat1 = new Cat('dahuang')
cat.name; //error
cat.say(); //fine
cat1.name; //error
cat1.say(); //error
在类里面、派生类里面可以访问,在类外部没法访问
class Cat {
protected name: string;
constructor(name: string) {
this.name = name;
};
say(){console.log(this.name)}
}
class Cat1 extends Cat { };
let cat1 = new Cat1('dahuang');
cat1.say(); //fine
cat1.name1 //error
let cat = new Cat('xiaobai');
cat.say() //fine
cat.name; //error
纸面就是只读么,这个说实话我没太看懂官网的文档什么意思,大致吸收到的就是只读属性必须在声明时或构造函数里被初始化。
class Cat {
readonly name: string;
constructor(name: string) {
this.name = name;
};
say() { console.log(this.name) }
}
然后可以缩写试了一下对于几个修饰符是一样的
class Cat {
constructor(public name: string) {};
say() { console.log(this.name) }
}
静态属性并不存在于实例化对象中,而是直接存在与类本身。
在es5中的静态方法和静态属性
function cat(){
this.say1 = function(){} //实例方法
}
cat.name = 'dahuang' //静态属性
cat.say2 = function(){} //静态方法
//方法调用
var p = new Cat();
p.say1();
Cat.say2()
ts中定义静态方法和属性
class Cat{
public name:string;
static age:number = 2;
constructor(name:string){
this.name = name;
}
say(){ //实例方法,实例化后才可调用
console.log(this.name)
console.log(this.age)//静态属性this访问会error
console.log(Cat.name)//访问静态属性
}
static work(){//静态方法,无法直接调用类的属性
console.log('拿耗子')
}
}
Cat.say();//实例方法直接调用会报错
Cat.work();//静态方法可以直接调用
console.log(Cat.age)//直接调用静态属性
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 说人话就是算是一种多态的规范,指定必须要包含那些方法,但是基类本身不去实现
abstract class Cat {
constructor(name:string='cat'){}
abstract say(): any;
}
let cat1 = new Cat() //error不能创建一个抽象类的实例
class Cat1 extends Cat{//fine
say(){console.log('大狗')}
}
class Cat2 extends Cat{//error未实现cat中的成员say
attck(){console.log('小狗')}
}