类
介绍
传统的JavaScript程序使用函数和基于原型的继承来创建面向对象的类,在es6中,JavaScript程序员能够使用基于类的面向对象的方式,通过引入class关键字,表示定义一个类。TypeScript中允许开发者使用这些特性。
类的定义
其实typescript中定义类的方法与ES6相同,在ES6的基础上,加了类型检查。
//es6中定义类的方法:
class Person {
constructor(name){
this.name = name;
}
run() {
console.log(this.name);
}
}
//ts中定义类的方法
class Person {
public name:string; // public关键字可省略
constructor(name:string){ //构造函数 实例化类的时候触发的方法
this.name = name;
}
run():void {
console.log(this.name);
}
}
// 执行方法
var p=new Person('张三');
p.run()
继承
在TypeScript中,我们可以使用常用的面向对象模式。可使用继承(关键字extends、super)来扩展现有的类。
class Person {
public name:string; // public关键字可省略
constructor(name:string){ //构造函数 实例化类的时候触发的方法
this.name = name;
}
run():void {
console.log(this.name);
}
}
class Web extends Person{
constructor(name:string){
super(name); // 初始化父类的构造函数,必须调用super();
}
}
var w=new Web('张三');
w.run()
上述例子展示了基本的继承:类从基类中继承了属性和方法。这里, Web
是一个派生类,它派生自Person
基类,通过extends
关键字。派生类
通常被称作子类
,基类
通常被称作超类
.
因为Web
继承了Person
的功能,因此Web
的实例能够执行run
方法。
当子类中定义的方法和父类一致时,会执行子类中的方法,这是
原型链
的查找规则。
类中的修饰符(public、protected、private)
public :公有,在当前类里面、 子类 、类外面都可以访问;
protected:保护类型,在当前类里面、子类里面可以访问 ,在类外部没法访问
private :私有 ,在当前类里面可以访问,子类、类外部都没法访问
默认为public
在TypeScript中,成员默认为public,也可以明确将一个成员标记为public。上面的例子也可这么写:
class Person {
public name:string; // public关键字可省略
public constructor(name:string){ //构造函数 实例化类的时候触发的方法
this.name = name;
}
public run():void {
console.log(this.name);
}
}
var p=new Person('张三');
p.run()
理解protected
protected类型的成员在当前类和子类中都可以访问,但不能在类外部访问。
// 类外部无法访问保护类型的属性
class Person {
protected name:string;
constructor(name:string){
this.name = name;
}
run():void {
console.log(this.name);
}
}
class Web extends Person{
constructor(name:string){
super(name); // 这里仍可以访问name,因为web是由person类派生来的
}
}
var p=new Person('张三');
p.name; // error 不能在类外部使用protected类型变量或方法
注意:当派生类构造函数被标记为protected。这意味着这个类不能在包含它的类外被实例化,但是能被继承。
理解private
当成员被 标记成private时,它就不能在声明它的类的外部访问。
class Person {
private name:string;
constructor(name:string){
this.name = name;
}
run():void {
console.log(this.name);
}
}
class Web extends Person{
constructor(name:string){
super(name);
}
work():void {
console.log(this.name); // error 私有变量不能在子类中使用
}
}
var p=new Person('张三');
p.name; // error 私有变量不能在类外部使用
静态属性 静态方法
静态属性及方法存在于类本身而不是类的实例上。使用static关键字定义,如果实例对象想访问静态属性,需在属性age前加类名Person,如下例:
class Person {
name:string;
static age:number = 20;
constructor(name:string){
this.name = name;
}
static run():void {
console.log(this.name);
}
work():void{
console.log(Person.age); // 访问静态属性,必须使用类Person调用
}
}
var p = new Person('张三');
p.run(); // error 访问静态方法,必须使用类调用
Person.run(); // right
抽象类 多态
抽象类作为其他派生类的基类,一般不会直接被实例化。使用abstract关键字定义抽象类和抽象方法。
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。abstract抽象方法只能放在抽象类里面。
abstract class Animal{
public name:string;
constructor(name:string){
this.name=name;
}
abstract eat():any; //抽象方法不包含具体实现并且必须在派生类中实现。
run(){
console.log('其他方法可以不实现')
}
}
// var a=new Animal() /*错误的写法*/
class Dog extends Animal{
//抽象类的子类必须实现抽象类里面的抽象方法
constructor(name:any){
super(name)
}
eat(){
console.log(this.name+'吃粮食')
}
}
var d=new Dog('小花花');
d.eat();
多态:父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现。
class Animal {
name:string;
constructor(name:string) {
this.name=name;
}
eat(){ //具体吃什么 不知道 ?继承它的子类去实现 ,每一个子类的表现不一样
console.log('吃的方法')
}
}
class Dog extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃粮食'
}
}
class Cat extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃老鼠'
}
}
var d = new Dog('小狗');
var c = new Cat('小花');
d.eat(); // 小狗吃粮食
c.eat(); // 小花吃老鼠
// 对于同一个方法每个子类实例有不同的表现
接口
接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescript中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。
属性类接口
ts中当自定义方法需对传入的参数进行约束时,我们可以这样定义:
约束传入的参数必须是对象,并且有label属性
function printLabel(labelInfo:{label:string}):void {
console.log('printLabel');
}
printLabel('hahah'); //错误写法
printLabel({name:'张三'}); //错误的写法
printLabel({label:'张三'}); //正确的写法
当需要对批量方法传入的参数进行更新时,可引入接口:行为和动作的规范,对批量方法进行约束.
interface FullName{
firstName:string; //注意;结束
secondName:string;
}
function printName(name:FullName){
// 必须传入对象 firstName secondName
console.log(name.firstName+'--'+name.secondName);
}
printName('1213'); //错误
var obj={ /*传入的参数必须包含 firstName secondName*/
age:20,
firstName:'张',
secondName:'三'
};
printName(obj); // 输出“张--三”
当接口里的属性不全都是必需的,在某些条件下存在,或者根本不存在时,可在可选属性名字定义的后面加?
符号
函数类型接口
函数类型接口:对方法传入的参数以及返回值进行约束
interface encrypt {
(key:string, value:string):string;
}
var md5:encrypt = function(key:string, value:string):string {
return key+value;
}
console.log(md5('name', 'zhangsan'));
对于函数类型的类型检查来说,函数的参数名不需要与接口定义的名字相匹配,比如用下面的代码重写上面的例子:
var md5:encrypt = function(source:string, src:string):string {
return source+src;
}
类类型接口
对类的约束,和抽象类有点相似
在C#或Java中,接口通常是用来定义一个类的公共部分,然后创建一个类,通过implements
关键字去实现接口。
在接口中描述方法,在类里实现它。
interface Animal{
name:string;
eat(str:string):void;
}
class Dog implements Animal{
name:string;
constructor(name:string){
this.name=name;
}
eat(){
console.log(this.name+'吃粮食')
}
}
var d=new Dog('小黑');
d.eat();
可索引接口
可索引接口:是对数组、对象的约束。不太常用
//可索引接口 对数组的约束
interface UserArr{
[index:number]:string
}
var arr:UserArr=['aaa','bbb'];
console.log(arr[0]);
var arr:UserArr=[123,'bbb']; /*错误,索引的值只能是string*/
console.log(arr[0]);
//可索引接口 对对象的约束
// 索引为string类型,值也为string类型
interface UserObj{
[index:string]:string
}
var arr:UserObj={name:'张三'};
扩展接口:接口可以继承接口
interface Animal{
eat():void;
}
interface Person extends Animal{
work():void;
}
class Programmer{
public name:string;
constructor(name:string){
this.name=name;
}
coding(code:string){
console.log(this.name+code)
}
}
class Web extends Programmer implements Person{
constructor(name:string){
super(name)
}
eat(){
console.log(this.name+'喜欢吃馒头')
}
work(){
console.log(this.name+'写代码');
}
}
var w=new Web('小李');
w.eat();
w.coding('写ts代码');
在上面例子中,定义了两个接口Animal
和Person
,其中Person
继承自Animal
,又定义programmer
类,具有name
属性和coding
方法,定义的Web
类继承自Programmer
并实现了Person
接口,因此Web
实例也有name
属性和Animal
、Person
接口的方法eat、work、coding
上一篇TypeScript基础入门(三)主要介绍ts中的函数