在ES6中为了更好的把js设计成面向对象的语言的语法特征,提出了class 类,class的本质是函数,类不可重复声明,类定义不会被提升,让js更像面向对象编程的语法。
类名建议大写,在严格要求下必须大写。
声明类:class 类名 {}
匿名类: var fn = class {}
类的实例为对象,对象三大特性:封装、继承与多态。
class Animal{
constructor(name){ //接收参数
this.name = name
}
run(){
console.log( this.name+'可以跑起来!')
}
}
console.log(111);
const dog = new Animal('小黑')
dog.run()
1、使用extends关键字实现继承
2、子类可以继承父类中所有的方法和属性
3、子类只能继承一个父类(单继承),一个父类可以有多个子类
4、子类的构造方法中必须有super()来指定调用父类的构造方法,并且位于子类构造方法中的第一行
5、子类中如果有与父类相同的方法和属性,将会优先使用子类的(覆盖)
class Dog extends Animal{
bark(){
return `${this.name} 是一只狗`
}
}
console.log(222);
const mazi = new Dog('王麻子')
mazi.run()
console.log(mazi.bark)
class JinMao extends Dog{
static categories = ['manmal'] //static-修饰符,静态属性
constructor(name){
super(name) //子类构造函数中必须用super()
consoe.log(this.name)
}
run(){
return 'memow'+super.run() //调用父类的run函数
}
}
console.log(333);
const maomao = new JinMao('maomao')
maomao.run()
//static 定义的变量和方法,可以直接用 方法名+点+变量/方法名() 调用
console.log( JinMao.categories );
ts中的class又增加了三种修饰符,用来给类中的属性与方法设置权限,更易管理。
- public:修饰的属性与方法是共有的,默认;
- private:修饰的属性和方法是私有的,只能在class里使用,通过该类new出来的实例、继承的子类也不能使用;
- protected:修饰的属性与方法是受保护的,继承的子类可以使用。
class Animal {
public name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
class Animal{
private run(){
return `${this.name} is running`
}
}
const snake = new Animal()
console.log(snake.run()) //报错,run已变成私有方法,不能被使用
class Animal {
protected name;
}
class Cat extends Animal {
constructor(name) {
super(name);
console.log(this.name);
}
}
注意如果
readonly
和其他访问修饰符同时存在的话,需要写在其后面。
class Animal {
readonly name;
}
let a = new Animal();
console.log(a.name); // Jack
a.name = 'Tom'; //无法修改
我们使用接口(Interfaces)来定义对象的类型, 接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)
接口声明只存在于编译阶段,在编译后生成的 JS 代码中不包含任何接口代码
interface Person {
name: String //必传
age?: Number // ?:可传可不传
}
//调用1:格式必须和接口的格式一致,多属性,少属性都不行
let tom: Person = {
name: 'Tom'
};
//调用2:
let tom: Person = {
name: 'Tom',
age: 25
};
*一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
interface Person {
name: string //确定属性,之前就是必传
age?: number //可传属性,之前就是不必传,使用任意属性以后,必传
[propName: string]: string | number //任意属性,加上以后,对象里面可以有任意多对象
//[propName: string]: string 如果这样写会报错,因为 age的值是number
}
//调用1:格式必须和接口的格式一致,多属性,少属性都不行
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
}
//调用2
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male',
aaa: '123'
}
注意,只读的约束存在于第一次给对象赋值的时候
interface Person {
readonly id: number
name: string
age?: number
[propName: string]: any
}
let tom: Person = {
id: 89757, // 初始化 对象赋值,是成功的
name: 'Tom',
gender: 'male'
};
tom.id = 9527; // 再次赋值,会报错,因为id是只读属性
相同:
都可以用来定义 对象 或者 函数 的结构,而严谨的来说,type 是引用,而
interface
是定义不同:
1、type (alias)类型别名,可以定义基础类型、联合类型或交叉类型。interface 接口,只能定义对象,
2、接口可以 extends、implements,从而扩展多个接口或类。 type没有扩展功能,只能交叉合并
3、定义两个相同名称的接口会合并声明,定义两个同名的 type 会出现异常。
4、type 在声明类型别名之后实际上是一个赋值操作,它需要将别名与类型关联起来。也就是说类型别名不会创建出一种新的类型,它只是给已有类型命名并直接进行引用。
interface
是定义了一个接口类型
// 1、定义声明不同
type Person = string
type animal = Dog | Cat
//type定义元组
interface Dog {
name: string;
}
interface Cat {
age: number;
}
type animal = [Dog, Cat];
//接口定义对象
interface Person {
name: string
}
// 2、定义两个相同名称的接口会合并声明,定义两个同名的 type 会出现异常
interface Person {
name: string;
}
interface Person {
age: number;
}
// 合并为:interface Person { name: string age: number}
type User = {
name: string;
};
type User = {
age: number;
};
// 声明重复报错:标识符“User”重复。
接口可以 extends、implements ,来实现继承
//extends 可以实现class继承,也可以实现接口继承
interface Person {
name: string;
}
interface User extends Person {
age: number;
}
interface Animal {
food: string
eat(food: string): void
}
// Cat类实现Animal接口的时候需要能够兼容Animal接口才行,否则会报错。
class Cat implements Animal {
food: string = 'fish';
eat(food: string): void {}
}
type Person = { name: string }; //1、type定义对象
type User = Person & { age: number }; //2、type合并两个对象
interface Person {
name: string;
}
type User = { age: number } & Person; //3、type合并对象和接口