Vue学习笔记4.11

本文介绍了TypeScript的基本类型系统,包括类型注解、静态代码分析、数组和元组的定义,以及枚举的使用。接着,讲解了类和接口的概念,如接口作为对象状态和行为的抽象,函数类型的接口,以及类的继承和多态。最后,提到了泛型、访问修饰符、存取器、静态成员和抽象类等高级特性。
摘要由CSDN通过智能技术生成

TypeScript

类型注解:是一种轻量级的为函数或变量添加的约束

TS提供了静态代码分析,能够在编译期发现代码写的不规范的地方。

TS能够支持所有JS支持的类型,此外它还能支持枚举,元组等类型

//数组类型
//数组定义方式1
// 语法; let 变量名:数据类型[] = [值1,值2,值3]
let arr1:number[] = [10,20,30,40,50]
//数组定义方式2: 泛型的写法
//语法: let 变量名: Array<数据类型> =  [值1,值2,值3]
let srr2 = Array<number> =  [12, 13, 14]
//注意问题:数组定义之后,里面的数据类型必须和定义时候的数据类型是一致的,否则有错误提示信息,也不能编译通过

// =====================

//元组类型:在定义数组的时候,类型和数据的个数在一开始就已经确定了
let arr3: [string, number, boolean] = ['', 13, true];
//注意问题:元组类型在使用的时候,数据类型的位置和数据个数应该和定义时候的数据类型和个数一致

//========================

//枚举类型, 枚举里面的每个数据都可以叫元素
enum Color {
	red, green, blue
}
//定义一个Color的枚举类型的变量来接收枚举的值
let color:Color = Color.red;
console.log(color)
console.log(Color.red, Color.green, Color.blue)
console.log(Color[3])

void类型,当一个函数没有返回值的时候,指定为void类型

//定义void类型的变量,可以接收一个undefined的值,但是意义不大
let vd:void = undefined;
console.log(vd)

联合类型 |

一般用于函数参数可能是多种类型 function F(ss: string | number){}

类型断言: 告诉编译器,我知道自己是什么类型,也知道自己在干什么

类型断言的语法1:<类型>变量名 str
类型断言的语法2: 变量名 as 类型 str as string

类型推断

TS会在没有明确指定类型的时候推测出一个类型

复习

接口对象类型

接口是对象的状态(属性)和行为(方法)的抽象(描述)
接口是一种类型,是一种规则,是一种约束

interface IPerson {
	name:string,
	age:number
}
function Person(p:IPerson){
	return {
		name:p.name,
		age: p.age
	}
}

接口函数类型

为了使用接口表示函数类型,我们需要给接口定义一个调用签名。
它就像是一个只有参数列表和返回值类型的函数定义,参数列表里面的每个参数都需要名字和类型

(()=>{
//函数类型:通过接口的方式作为函数类型来使用

//定义一个接口,用来作为某个函数的类型使用
	interface ISearchFunc {
	//定义一个调用签名
		(source:string, subString: string): boolean
	}

//定义一个函数,该类型就是上面定义的接口
const searchString: ISearchFunc = function(soure:string, subString:string){
	return source.search(subString) > -1
}

//调用函数
console.log(searchString('哈哈,环境', ‘哈’))
})()

类类型:类的类型可以通过接口来实现

(()=>{
//定义一个接口
	interface IFly{
	//该方法没有任何的实现(方法中什么都没有)
		fly()
	}

//定义一个类,这个类的类型就是上面定义的接口(实际上也可以理解为,IFly这个接口约束了当前这个Person类)
class Person implements IFly {
//实现接口中的方法
	fly(){
		console.log('i can fly, i'm superman')
	}
}

//实例化对象
const person = new Person()
person.fly()
})()

//定义一个接口
interface ISwim{
	swim()
}

//定义一个类,同时实现IFly和ISwim两个接口

class Person2 implements IFly,ISwim{
	fly(){

	}
	swim(){

	}
}

//实例化对象
const person2 = new Person2()
person2.fly()
person2.swim();

//总结: 类可以通过接口的方式,来定义这个类的类型
//类可以实现一个接口,类也可以实现多个接口,要注意,接口中的内容都要真正的实现

//接口可以继承其他的多个接口
interface IMyFlyAndSwim extends IFly, ISwim {
	
}

class Person3 implements IMyFlyAndSwim {
	fly(){}
	swim(){}
 }
 const person3 = new Person3();
 person3.fly()
 person3.swim()
 // 总结: 接口和接口之间叫继承(使用的是extends关键字),类和接口之间叫实现(使用的是implements关键字)

类:可以理解为模版,通过模版实例化对象

//面向对象的编程思想
(()=>{
	class Person {
		name:string,
		age:number,
		gender: string
		constructor(name: string='xiaohua', age: number=16, gender: string='female'){
			this.name = name
			this.age = age
			this.gender = gender
		}

//定义实例方法
sayHi(str: string){
	console.log('hello' + str);
}
	}
const person = new Person('zuozuo', 1, 'male')
person.sayHi('what's your name?')
})()

继承:类与类之间的关系

继承后类与类之间的叫法:
A类继承了B这个类,那么此时A类叫子类,B类叫基类
子类 -----》 派生类
基类-----〉超类(父类)
一旦发生了继承的关系,就出现了父子类的关系

(()=>{
	class Person{
		name:string,
		age:number,
		gender:string
constructor(name:string, age:number, gender:string){
	this.name = name;
	this.age = age;
	this.gender = gender
}
sayHi(str:string){
	console.log(this.name + str)
}
}

class Student entends Person {
	constructor(name:string, age: number, gender: string){
	//调用父类中的构造函数,使用的是super
		super(name, age, gender)
	}
//可以调用父类中的方法
	sayHi(){
	//调用父类中的sayHi方法
		super.sayHi('haha')
	}
}

//实例化Person
const person = new Person('daming', 4, 'nan')
person.sayHi('gaga')
const stu = new Student('xiaoming', 3, 'nv')
stu.sayHi()

//总结: 类和类之间如果要有继承关系,使用的是extends关键字
//子类可以调用父类的构造函数,使用的是super关键字(包括调用父类实例上的方法)
//子类可以重写父类的方法
})()

多态:父类型的引用指向子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为

(()=>{
//定义一个父类
	class Animal {
	//定义一个属性
		name:string
		//定义一个构造函数
		constructor(name: string){
		//更新属性值
			this.name = name
		}
//实例方法
		run(distance: number = 0){
			console.log(`distance is ${distance}`)
		}
	}
//定义一个子类
class Dog extends Animal{
//构造函数
	constructor(name:string){
	//调用父类的构造方法,实现了子类中属性的初始化操作
		super(name)
	}

	run(distance:number){
		console.log('distance is ' + distance)
	}
}
//定义一个子类
class Pig extends Animal{
//构造函数
	constructor(name:string){
	//调用父类的构造方法,实现了子类中属性的初始化操作
		super(name)
	}

	run(distance:number){
		console.log('distance is ' + distance)
	}
}

// 实例化父类对象
const ani:Animal = new Animal('animal')
ani.run()
//实例化子类对象
const dog: Dog = new Dog('dog')
dog.run()

const dog: Animal = new Dog('dahuang')
dog.run()
const pig: Animal = new Pig('xiaozhu')
pig.run();
})()

修饰符(类中的成员的修饰符)

主要是描述类中的成员(属性,构造函数,方法)的可访问性

// public修饰符,类中的成员的默认修饰符,代表是公共的,任何位置都可以访问类中的成员
//private修饰符,类中的成员如果使用private来修饰,那么外部是无法访问这个成员变量的,当然,子类中也是无法访问该成员变量的
//protected修饰符,类中的成员如果使用protected来修饰,那么外部是无法访问的,子类中是可以访问的
(()=>{
	//定义一个类
	class Person{
		name:string
		constructor(name:string){
			this.name = name
		}
		public eat(){
			console.log('this bone is dilicious', this.name)
		}
	}
//实例化对象
	const per = new Person('huahu')
	//类的外部可以访问类中的属性成员 
	console.log(per.name)
	per.eat()
})()

readonly修饰符

readonly首先是一个关键字,
对类中的属性成员进行修饰,修饰符后,该属性成员,就不能在外部被随意的修改了
可以在构造函数中对readonly修饰的属性进行修改

(()=>{
	class Person {
		readonly name:string = ‘da tian tian’
		constructor(name:string){
			this.name = name
		}
		sayHi(){
			console.log('kao la kao la', this.name)
			//类中的普通方法,也是不能修改readonly修饰的成员属性值
			this.name = 'da tian tain'
			}
	}

//实例化对象
const person = new Person('xiao tian tian')
console.log(person)
cosnole.log(person.name)
person.name = 'da tian tian' // 报错, 此时无法修改name,因为name属性是只读的
console.log(person.name)
})()
// 对构造函数中的属性用readonly进行修饰
class Person {
	//构造函数
	//构造函数中的name参数,一旦使用readonly进行修饰后,那么该name参数可以叫做参数属性
	//构造函数中的name参数,一旦使用readonly进行修饰后,那么Person中就有了一个name的属性成员
	//构造函数中的name参数,一旦使用readony进行修饰后,外部也是无法访问类中的name属性成员值的
	constructor(readonly name:string = 'da tian tian'){
		this.name = name
	}
}
const person:Person = new Person('xiao tian tian')
console.log(person)
person.name = 'zuozuo'
console.log(person.name)

存取器

让我们可以有效的控制对 对象中成员的访问,通过getters和setters来进行操作

(()=>{
	class Person{
	//姓名的成员属性(外部可以访问,也可以修改)
		firstName: string;
		lastName: string;
		constructor(firstName:string, lastName:string){
			this.firstName = firstName;
			this.lastName = lastName
		}
		//读取器,负责读取数据的
		get fullName(){
			return this.firstName + "_" + this.lastName
		}

		//设置器,负责设置数据的(修改)
		set fullName(val){
			let names = val.split('_')
			this.firstName = names[0]
			this.lastName = names[1]
			}
	}
	//实例化对象
	const person:Person = new Person('dongfang', 'bubai')
	console.log(person)
	//获取该属性成员属性
	console.log(person.fullName)
	//设置该属性的数据
	person.fullName = 'zhugeng_kongming'
	console.log(person.fullName)
})()

静态成员

在类中通过static修饰的属性或者方法,那么就是静态的属性及静态的方法,也称之为静态成员
静态成员在使用的时候是通过点(类.)这种语法来调用的

(()=>{
	class Person {
		// 类中默认有一个内置的name属性,所以此时会出现错误的提示信息
		static name1: string
		constructor(name:string){
			this.name1 = name
		}
		static sayHi(){
			console.log('ni hao')
		}
	}
//实例化对象
const person:Person = new Person('xiao tian tian')
//通过实例对象调用的属性(实例属性)
console.log(person.name1)
//通过实例对象调用的方法(实例方法)
person.sayHi()
//通过类名.静态属性的方式来设置该成员数据
console.log(Person.name1)
Person.sayHi()
})()

抽象类

包含抽象方法(抽象方法一般没有任何的具体内容实现),也可以包含实例方法,抽象类不能被实例化,为了让子类进行实例化并实现内部抽象的方法

(()=>{
   abstract class Animal {
    abstract name:string;

    //报错,因为抽象方法不能有具体的实现
        // abstract eat(){
        //     console.log();
            
        // }
        abstract eat():any
        //实例方法
        sayHi(){
            console.log('hello');
            
        }
    }
    //不能创建抽象类的实例
    // const ani: Animal = new Animal();
    //定义一个子类(派生类)Dog
     class Dog extends Animal {
        name = 'hehe'
        //重新的实现抽象方法, 这个方法为当前Dog类的实例方法
        eat() {
            console.log('guizhe chi');
            
        }
     }
     const dog:Dog = new Dog();
     dog.eat()
     //调用的是抽象类中的实例方法
     dog.sayHi();
     console.log(dog.name);
     
})()

函数

封装一些重复使用的代码,在需要的时候直接调用即可

(()=>{
    //函数的完整写法
    // add3 -----> 变量名-----》函数add3
    // (x:number, y:number)=>number 当前这个函数的类型
    //function(x:number, y:number):number{ return x + y } 相当于符合上面这个函数类型的值
   const add3:(x:number, y:number)=>number = function(x:number, y:number):number{
    return x + y
   }   
   console.log(add3(1, 2));
    
})()

可选参数和默认参数

(()=>{
    //可选参数
    //默认参数
    //定义一个函数:传入姓氏和名字,可以得到姓名(姓氏+名字=姓名)
    //需求:1. 如果不传入任何内容,那么久返回默认的姓氏
        // 2. 如果只传入姓氏,那么就返回姓氏
        // 3. 如果传入姓氏和名字,那么就返回姓名
    const getFullName = function(firstName:string = 'dongfang', lastName?:string):string{
        //判断名字是否传入了
        if(lastName){
            return firstName + '_' + lastName
        }else{
            return firstName
        }
    }

    //函数调用
    //什么都不传
    console.log(getFullName());
    //只传入姓氏
    console.log(getFullName('zhuge'));
    //传入姓氏和名字
    console.log(getFullName('zhuge', 'kongming'));
    
})()

剩余参数(rest参数)

剩余参数是放在函数声明的时候,所有的参数的最后

(()=>{
// ...args:string[] --->剩余的参数,放在了一个字符串的数组中,args里面
    function showMsg(str:string, ...args:string[]){
        console.log(str, args); //a [ 'c', 'v', 'f', 'r' ]
        
    }
    showMsg('a', 'c', 'v', 'f', 'r')
})()

函数重载

函数名字相同,函数的参数和个数不同

(()=>{
  //定义一个函数
  // 需求: 有一个add函数,它可以接收2个string类型的参数进行拼接,也可以接收2个number类型的参数进行相加

  //函数重载声明
  function add(x:string, y:string): string
  function add(x:number, y:number): number
  //函数声明
  function add(x:string|number, y:string|number): string|number{
   if(typeof x=== 'string' && typeof y === 'string'){
       return x + y //字符串拼接
   }else if(typeof x === 'number' && typeof y === 'number'){
       return x + y //数字相加
   }
  }
  //函数调用
  //两个参数都是字符串
  console.log(add('zhuge', 'kongming'));
  //两个参数都是数字
  console.log(add(10, 20));
  //此时如果传入的是非法的数据,ts应该会提示错误
//    console.log(add('zhuge', 10));
//    console.log(add(10, 'zhuge'));
  
})()

泛型

在定义函数,接口,类的时候不能确定要使用的数据的类型,而是在使用的时候才能确定数据的类型

(()=>{
   //需求:定义一个函数,传入两个参数,第一个参数为数据,第2个参数为数量,返回一个数组,包含数量个数据
   function getArr(a:string, b:number):string[]{
       const arr:string[] = [];
       for(let i=0; i<b; i++){
           arr.push(a)
       }
       return arr
   }

   function getArr1(a:number, b:number):number[]{
       const arr:number[] = [];
       for(let i=0; i<b; i++){
           arr.push(a)
       }
       return arr
   }

   function getArr2(a:any, b:number):any[]{
       const arr:any[] = [];
       for(let i=0; i<b; i++){
           arr.push(a)
       }
       return arr
   }

   function getArr3<T>(a:T, b:number):T[]{
       const arr:T[] = [];
       for(let i=0; i<b; i++){
           arr.push(a)
       }
       return arr
   }

   console.log(getArr3('abd', 3))
   console.log(getArr3(10.2, 3))
   console.log(getArr3(10.2, 3)[0].toFixed(2))
   console.log(getArr3('asd', 3)[0].split(''))
  
})()

多个泛型参数

函数中有多个泛型参数

(()=>{
    function getMsg<K, V>(value: K, value2:V):[K, V]{
        return [value, value2]
    }
    const arr1 = getMsg<string, number>('jack', 10.2);
    console.log(arr1[0].split(''));
    console.log(arr1[1].toFixed(1));
})()

泛型接口

在定义接口时,为接口中的属性或者方法定义泛型类型,在使用接口时,再指定具体的泛型类型

(()=>{
    // 需求:定义一个类, 用来存储用户相关的信息、
    //定义一个用户信息类
    class User{
        id?: number
        name: string
        age: number
        constructor(name:string, age:number){
            this.name = name
            this.age = age
        }
    }
    //定义一个泛型接口
    interface IBaseCRUD<T>{
        data:Array<T>
        add:(t:T) => T
        getUserId:(id:number) => T|undefined
    }
//定义一个类,可以针对用户的信息对象进行增加及查询的操作
//CRUD----》create, Read, Update, Delete
    class UserCRUD implements IBaseCRUD<User>{
        //用来存储多个User类型的用户信息对象
        data: Array<User> = [];
        //方法用来存储用户信息对象的
        add(user:User):User{
            user.id = Date.now() + Math.random()
            //把用户信息对象添加到data数组中
            this.data.push(user)
            return user;
        } 
        //方法根据id查询指定的用户信息对象
        getUserId(id:number|undefined):User|undefined{
            return this.data.find(user=>user.id===id)
        }
    }
    const userCRUD:UserCRUD = new UserCRUD();
    userCRUD.add(new User('jack', 20))
    const {id} = userCRUD.add(new User('lucy', 21))
    console.log(userCRUD.getUserId(id));
    
    console.log(userCRUD.data);
    
})()

泛型类

定义一个类,类中的属性值的类型是不确定的,方法中的参数及返回值的类型也是不确定的

(()=>{
   //定义一个泛型类
   class GenericNumber<T>{
       //默认属性值的类型是泛型类型
       defaultValue: T
       add:(x:T, y:T) => T
   }
   //在实例化类的对象的时候,再确定泛型类型
   const g1:GenericNumber<number> = new GenericNumber<number>()
   g1.defaultValue = 100
   g1.add = function(x, y){
       return x + y
   }
   console.log(g1.add(g1.defaultValue, 20));
   

   const g2:GenericNumber<string> = new GenericNumber<string>()
   g2.defaultValue = 'haha'
   g2.add = function(x, y){
       return x + y
   }
   console.log(g2.add(g2.defaultValue, 'd'));
})()

泛型约束

如果我们直接对一个泛型参数取length属性,会报错,因为这个泛型根本就不知道它有这个属性

(()=>{
   //定义一个接口,用来约束将来的某个类型中必须要有length这个属性
   interface ILength {
       //接口中有一个length属性
       length: number
   }
   function getLength<T extends ILength>(x:T):number{
       return x.length
   }
   console.log(getLength<string>('what is it'));
   // console.log(getLength<number>(123)); //报错,number不满足泛型接口,number类型没有length属性
   
})()

声明文件

当使用第三方库的时候,我们需要引用它的声明文件,才能获得对应的代码补全,接口提示等功能
声明语句:如果需要ts对新的语法进行检查,需要加载对应的类型说明代码
declare var jQuery:(selector: string) => any;
声明文件:把声明语句放到一个单独的文件(jQuery.d.ts) 中,ts会自动解析到项目中所有声明文件(xx.d.ts)
下载文件声明: npm install @types/jquery --save-dev

内置对象

(()=>{
   //ECAMScript的内置对象
   let b: Boolean = new Boolean(1)
   let n: Number = new Number(true);
   let s: String = new String('asd');
   let d: Date = new Date()
   let r: RegExp = /^1/
   let e: Error = new Error('error message')
    // b = true
    console.log(b);
    
})()
(()=>{
   const div: HTMLElement|null = document.getElementById('test')
    const divs: NodeList = document.querySelectorAll('div')
    document.addEventListener('click', (event: MouseEvent)=>{
        console.dir(event.target);
    })
    const fragment:DocumentFragment = document.createDocumentFragment()
})()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值