一 前言
TS提供了一系列面向对象的方法,在这里,我们可以像JAVA一样完成一些面向对象的编程,在ES6和TS之前,我们只能利用JS的原型继承以及扩展的继承方法来实现封装与继承,但过程比较繁琐。但TS为我们提供了更为完整的面向对象的写法三要素:封装、继承、与多态。
在前端的的项目工程中,由于javascript的动态化以及弱类型化,是的编程本身的正确性有所折扣,特别是diamante的压缩中,往往会出现代码逻辑通过,但是语言编译报错,或者执行报错。
TypeScript的核心原则之一是对变量所具有的结构进行类型检查。通过Ts的类型检查,能够在编写阶段就完成js的编译检查,往往能够缩减很多不必要的麻烦。
而接口就是其中很重要的一个类型检查。
二 接口
现在定义一个方法
function getName(student){ console.log(student.name.padEnd(10, '')); return student.name; } getName('xiao ming')// Uncaught TypeError: Cannot read property 'padEnd' of undefined通常我们这样写需要对参数student进行一个判断,有时候为了赶项目可能就忽略了这种判断,那么如果student不是一个Object的实例对象,那么这个函数就会报错。通过接口,我们就能够在编写代码的时候及时的检查到这种错误。
接口的初步定义
interface Student { name: string; }这个接口表明Student具有一个类型是string的name成员的数据结构;现在改写上面student函数的写法
function getName(student: Student) { console.log(student.name.padEnd(3, '')); return student.name; } getName('xiao ming'); // 类型“"xiao ming"”的参数不能赋给类型“Student”的参数 interface Student { name: string; }可以看到,在调用getName方法的时候,TS抛出了一个类型检查错误:类型“"xiao ming"”的参数不能赋给类型“Student”的参数
这是因为在调用getName函数的时候,TS会对函数的类型包括参数和返回值进行检查,student参数需要一个name成员,只有完全通过了匹配,TS才会允许安全。
那如果我们参数没有部分属性或者成员呢,要怎么办呢
// 不设置可选属性 interface Student { name: string; } let xiaoMing: Student = { name: 'xiao ming', age: 23 } // error 不能将类型“{ name: string; age: number; }”分配给类型“Student”。 对象文字可以只指定已知属性,并且“age”不在类型“Student”中下面介绍可选属性和默认属性
在ES6中,我们可以通过rest参数以及解构赋值为函数参数设置默认参数和可选参数;在TS中也有这些方法:
// 正确 interface Student { name: string; age?: number; // 可选成员属性 } let xiaoMing: Student = { name: 'xiao ming' }延伸开来,如果我们不知道,也不确定未来人会传什么参数到我们的函数中来怎么办呢?
TS提供了额外属性检查,同样写法很简单
// 正确 interface Student { name: string; [p?]: any; // 可选成员属性 } let xiaoMing: Student = { name: 'xiao ming', age: 18, sex: 'man' }这样,我们既确保了我们必须需要的一些成员,同时也不会强迫参数做很大的转变。
只读属性
// 正确 interface Student { readonly name: string; [p: string]: any; // 可选成员属性 } let xiaoMing: Student = { name: 'xiao ming', age: 18, sex: 'man' } xiaoMing.name = 'xiao hua' //error Cannot assign to 'name' because it is a read-only property.接口在类中的应用--implements
interface StudentInterface{ name: string; new (name: string): void } class Student implements StudentInterface{ name: string; constructor(name: string) { console.log(this); } }三 类与继承
在ES5中,如果我们需要封装一个对象,需要利用对象的原型链,TS以及ES6后,提出类class的概念。方便我们更好的作封装与继承的工作
类的声明例如上面的Student;使用方法和JS的构造函数的使用方法一样,需要new关键字;
let student = new Student('xiao ming');
其中constructor就是类的构造器,其他包括类的成员与方法:包括实例方法与静态方法。类的实例方法可以用来做为interface进行类型检查。
属性修饰符
public|protected|private |static |readonly
public:公共成员;在任何能够访问到这个类的地方都可以访问这个成员,可继承,可修改。
class Student { public name = ''; constructor(name: string){ this.name = name; } } class MidStudent implements Student{ constructor(name: string) { this.name = name + ':'; } } let xiaoMing = new MidStudent('xiao ming'); xiaoMing.name;// xiao ming:我们可以在子类中访问到name,也可以在实例上访问到name;public可以忽略;如果没有protected和private默认为public成员。
protected:受保护类型;我们可以在子类中访问到该属性,可继承;该成员属性只能在类和派生类中使用,类外是无法访问的。
class Student { protected name = ''; constructor(name: string){ this.name = name; } } class MidStudent implements Student{ constructor(name: string) { this.name = name + ':'; } } let xiaoMing = new MidStudent('xiao ming'); xiaoMing.name;// errorprivate:即私有属性,无法被继承,类外与派生类中均无法被访问
class Student { private name = ''; constructor(name: string){ this.name = name; } } class MidStudent implements Student{ constructor(name: string) { this.name = name + ':'; } } let xiaoMing = new MidStudent('xiao ming');// error xiaoMing.name;// errorstatic 静态属性,即归属于类的方法,而非实例的方法,例如constructor;需用通过类来访问。
readonly:只读属性,定义方法和接口的定义方法一样。
