学习笔记如下:
基础类型
(() => {
//布尔类型 ----->boolean
//基础语法
//let 变量名:数据类型 = 值
let flag: boolean = true
console.log(flag)
// 数字类型 ----->number
let a1: number = 10 // 十进制
let a2: number = 0b1010 // 二进制
let a3: number = 0o12 // 八进制
let a4: number = 0xa // 十六进制
console.log(a1);
console.log(a2);
console.log(a3);
console.log(a4);
// 字符串类型 ----->string
let name:string = 'tom'
name = 'jack'
// name = 12 // error
let age:number = 12
const info = `My name is ${name}, I am ${age} years old!`
console.log(info);
//undefined 和 null
let u: undefined = undefined
let n: null = null
//数组
let list1: number[] = [1, 2, 3]
let list2: Array<number> = [1, 2, 3]
//元祖
let t1: [string, number]
t1 = ['hello', 10] // OK
//t1 = [10, 'hello'] // Error
console.log(t1[0].substring(1)) // OK
//console.log(t1[1].substring(1)) // Error, 'number' 不存在 'substring' 方法
//枚举
//enum 类型是对 JavaScript 标准数据类型的一个补充。 使用枚举类型可以为一组数值赋予友好的名字。
enum Color {
Red,
Green,
Blue
}
// 枚举数值默认从0开始依次递增
// 根据特定的名称得到对应的枚举数值
let myColor: Color = Color.Green // 0
console.log(myColor, Color.Red, Color.Blue)
//默认情况下,从 0 开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 1 开始编号:
// enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green
//enum Color {Red = 1, Green = 2, Blue = 4}
//let c: Color = Color.Green
//enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]
console.log(colorName) // 'Green'
//any
let notSure: any = 4
notSure = 'maybe a string'
notSure = false // 也可以是个 boolean
let list: any[] = [1, true, 'free']
list[1] = 100
//void
//声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefined 和 null:
//某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void
/* 表示没有任何类型, 一般用来说明函数的返回值不能是undefined和null之外的值 */
function fn(): void {
console.log('fn()')
// return undefined
// return null
// return 1 // error
}
//object
//object 表示非原始类型,也就是除 number,string,boolean之外的类型。
//使用 object 类型,就可以更好的表示像 Object.create 这样的 API。例如:
function fn2(obj:object):object {
console.log('fn2()', obj)
return {}
// return undefined
// return null
}
console.log(fn2(new String('abc')))
// console.log(fn2('abc') // error
console.log(fn2(String))
//联合类型
//联合类型(Union Types)表示取值可以为多种类型中的一种
//需求1: 定义一个一个函数得到一个数字或字符串值的字符串形式值
function toString2(x: number | string) : string {
return x.toString()
}
//需求2: 定义一个一个函数得到一个数字或字符串值的长度
// function getLength(x: number | string) {
// return x.length // error
// if (x.length) { // error
// return x.length
// } else {
// return x.toString().length
// }
// }
//类型断言
// 通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript 会假设你,程序员,已经进行了必须的检查。
// 类型断言有两种形式。 其一是“尖括号”语法, 另一个为 as 语法
/*
类型断言(Type Assertion): 可以用来手动指定一个值的类型
语法:
方式一: <类型>值
方式二: 值 as 类型 tsx中只能用这种方式
*/
/* 需求: 定义一个函数得到一个字符串或者数值数据的长度 */
function getLength(x: number | string) {
if ((<string>x).length) {
return (x as string).length
} else {
return x.toString().length
}
}
console.log(getLength('abcd'), getLength(1234))
//类型推断
// 类型推断: TS会在没有明确的指定类型的时候推测出一个类型
// 有下面2种情况: 1. 定义变量时赋值了, 推断为对应的类型. 2. 定义变量时没有赋值, 推断为any类型
/* 定义变量时赋值了, 推断为对应的类型 */
let b9 = 123 // number
// b9 = 'abc' // error
/* 定义变量时没有赋值, 推断为any类型 */
let b10 // any类型
b10 = 123
b10 = 'abc'
})()
接口
// console.log('hellow Ts')
//变量类型的注释
// let age: number;
//变量类型转换
// console.log(2-+'2')
//接口
(() => {
interface Iperson{
firstName: string,
lastName:string
}
function showFullName(person: Iperson) {
return person.firstName +'_'+person.lastName
}
//定义一个对象
const person = {
firstName:'东方',
lastName:'不败'
}
// 将对象传入函数
console.log(showFullName(person))
})()
类
(() => {
// 定义一个接口
interface Iperson{
firstName: string,
lastName:string
}
//定义一个类型
class Person{
//定义公共的字段
firstName: string
lastName: string
fullName: string
//定义一个构造函数
constructor(firstName: string, lastName: string) {
this.firstName = firstName
this.lastName = lastName
this.fullName = this.firstName + '_' + this.lastName
}
}
//定义函数
function showFullName(person:Iperson) {
return person.firstName + '_' + person.lastName
}
//实例化对象
const person = new Person('诸葛', '孔明')
console.log(showFullName(person))
})()
类的继承
// 继承:类与类之间的关系
// 继承后类与类的叫法:
// a类继承了b类,那么刺水a类叫做子类,b类叫做基类
// 子类——派生类
// 基类——超类(父类)
// 一旦发生了继承关系,就出现了父子类的叫法
(() => {
// 定义一个类
class Person{
// 定义属性
name: string
age: number
gender:string
// 定义构造函数
constructor(name: string, age: number, gender: string) {
// 更新属性数据
// 此时,this.name 为属性name,相当于将构造函数获得的参数,传递给属性的每一个值
this.name = name
this.age = age
this.gender = gender
}
// 定义实例化方法
sayHi(str: string) {
console.log(`我是:${this.name},${str},我今年${this.age}岁,我是${this.gender}的`);
}
}
// 定义一个类,继承Person
class Student extends Person{
// 子类的自己的属性
Grade:string
constructor(name: string, age: number, gender: string,Grade:string) {
// 调用的是父类的构造函数,使用的是super关键字
super(name, age, gender)
// 更新子类属性的数值,将传入来的参数传给上面的属性,并通过{this.属性名}的方式使用该属性
this.Grade = Grade
}
// 可以调用父类的方法
sayHi() {
console.log('我是学生类的中sayhi方法');
// 调用父类的sayhi方法
super.sayHi('哈哈')
console.log(`我今年上${this.Grade}`);
}
}
// 实例化Person
const person1 = new Person('大聪明', 18, '男')
person1.sayHi('嘻嘻')
// 实例化Student
const stu1 = new Student('大明白', 20, '男','五年级')
stu1.sayHi()
})()
类的多态
// 多态:父类型的引用指向了子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
(() => {
// 定义一个父类
class Animal{
// 定义一个构造函数
name:string
constructor(name: string) {
// 属性数据更新:将实例化方法中的参数赋值给属性值
this.name = name
}
// 实例化方法
run(distance: number=11) {
console.log(`${this.name}跑了${distance}米的距离`);
}
}
// 定义一个子类
class Dog extends Animal {
// 构造函数
constructor(name: string) {
//调用了父类的构造函数,实现子类的属性初始化操作,因此子类不需要创建自己的属性,继承了父类的属性以及数据更新操作
super(name)
}
// 实例化方法
run(distance: number=10){
console.log(`${this.name}跑了${distance}米的距离`);
}
}
// 定义一个子类
class Cat extends Animal {
// 构造函数
constructor(name: string) {
//调用了父类的构造函数,实现子类的属性初始化操作,因此子类不需要创建自己的属性,继承了父类的属性以及数据更新操作
super(name)
}
// 实例化方法
run(distance: number=5){
console.log(`${this.name}跑了${distance}米的距离`);
}
}
// 定义一个子类
class Pig extends Animal {
// 构造函数
constructor(name: string) {
//调用了父类的构造函数,实现子类的属性初始化操作,因此子类不需要创建自己的属性,继承了父类的属性以及数据更新操作
super(name)
}
// 实例化方法
run(distance: number=100){
console.log(`${this.name}跑了${distance}米的距离`);
}
}
// 实例化父类对象
const ani:Animal = new Animal('动物')
ani.run()
// 实例化子类对象
const dog:Dog = new Dog('小黑')
dog.run()
const cat:Cat = new Cat('小黄')
cat.run()
const pig:Pig = new Pig('小白')
pig.run()
// 多态:父类型的引用指向了子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
// 父类和子类的关系:父子关系,此时,父类类型创建子类的对象
const dog1: Animal = new Dog('大黑')
dog1.run()
const cat1:Animal = new Cat('大黄')
cat1.run()
// 多态的作用:在父类中定义一个方法,在子类中有多个实现,在程序运行的时候,根据不同的对象执行不同的操作,实现运行时的绑定。
// 此时,函数需要传入的是ani是Animal类型
function showRun(ani: Animal) {
ani.run()
}
showRun(dog1)
showRun(cat1)
})()
类属性成员中的修饰符
// 修饰符:描述类的属性成员的可访问性,其中修饰符可在构造函数中修饰并定义属性成员
// public 全局可访问 默认修饰符
// private 父类可访问,子类和外部不可访问
// protectd 父子可以访问,外部不可访问
// readonly 父子外部都可以访问,但只有在父类的构造函数中可以修改
(() => {
// 定义一个类
class Person{
// 属性
public name: string
age: number
gender: string
private data: string
protected address: string
readonly ids:number
// 构造函数
// 定义了一个profection属性成员,用修饰符在构造函数里面定义
constructor(public profection:string,name: string, age: number, gender: string,data:string,address:string,ids:number) {
this.name = name
this.age = age
this.gender = gender
this.data = data
this.address = address
// 构造函数可以修改readonly的数据
this.ids = ids
}
// 方法
sayHi() {
// readonly 修饰后,普通方法不可以更改数据
//this.ids = 1;
console.log(`身份id:${this.ids},你好,我叫${this.name},是个${this.gender},今年${this.age}岁了,今年是${this.data},家在${this.address}`);
}
}
// 定义一个子类
class Student extends Person{
// 属性
// 构造函数
constructor(profection:string,name: string, age: number, gender: string,data:string,address:string,ids:number) {
super(profection,name, age, gender, data, address, ids)
// readonly 修饰后,子类构造函数不可以更改数据
//this.ids =1
}
// 方法
eat() {
// readonly 修饰后,普通方法不可以更改数据
//this.ids = 1;
// private---------------可以继承,但子类也不能访问
// protected---------------可以继承,可以访问
// console.log(`你好,我叫${this.name},是个${this.gender},今年${this.age}岁了${this.data},家在${this.address}`);
console.log(`身份id:${this.ids},你好,我叫${this.name},是个${this.gender},今年${this.age}岁了,家在${this.address}`);
}
}
// 实例化时,不管是否修饰符是什么,必要的参数还是需要传进去
// 实例化父类
const per1 = new Person('计算机','小明',20,'男孩','2021','深圳',1)
per1.sayHi()
// 实例化子类
const stu1 = new Student('计算机','小红', 18, '女孩','2022','梅州',2)
stu1.eat()
// 全局访问
console.log(per1.name);
// private----------------------外部访问不到
//console.log(per1.data);
// readonly 修饰后,外部不可以更改数据
//console.log(per1.ids=1);
console.log(per1.ids);
})()
静态成员
// 静态成员:在类中通过static修饰的属性或者方法,那么就是静态属性以及静态方法,也成为静态成员
// 静态成员在使用的时候通过类名.的语法来调用,而不用通过实例化对象的方法去调用
(() => {
class Person{
// 静态属性
// 类中默认有一个内置的name属性,不能重名
static name1: string = '葫芦娃'
// 构造函数不能通过static来进行修饰
constructor() {
// 此时this是实例对象,name1是静态属性,不能通过实例对象直接调用静态属性的方式来使用
// this.name1 = name
}
// 静态方法
static sayHi() {
console.log('hello');
}
}
// 实例化对象
const person: Person = new Person()
//console.log(person.name1);
//通过实例调用方法
//person.sayHi()
// 通过类名.属性名的方式来访问
console.log(Person.name1);
Person.name1 = '变形金刚'
console.log(Person.name1);
Person.sayHi();
})()
抽象类
// @ts-nocheck
// 抽象类的作用:为子类服务
// 抽象类:包含抽象方法(抽象方法一般没有任何具体内容的实现)也可以包含实例方法,抽象类是不能被实例化的,只能在被继承以及在子类实例化以及内部的方法
(() => {
abstract class Animal{
// 抽象属性:很少使用抽象属性放在子类去实现
abstract name:string
// 抽象方法
abstract eat()
// abstract eating() {
// console.log('抽象方法不能有具体的实现');
// }
// 实例方法
sayHi() {
console.log('hello');
}
}
// 抽象类不能被实例化
//const ani = new Animal()
// 通过子类继承后实例化
// 定义一个子类
class Dog extends Animal {
name:string ='小黄'
// 重新的实现抽象类中的方法,此时这个方法就是当前Dog类的实例方法
eat() {
console.log('吃狗粮');
}
}
// 实例化Dog类
const dog:Dog = new Dog()
dog.eat()
// 调用的是抽象类中的实例方法
dog.sayHi()
console.log(dog.name);
})()
ts函数写法
// 函数:封装了一些重复使用的代码,在需要的时候直接调用即可
(() => {
// js和ts书写方式
// // 函数生命,命名函数
// function add(x, y) {
// return x + y
// }
// // 函数表达式,匿名函数
// const add2 = function (x, y) {
// return x + y
// }
// ts写法
// 函数生命,命名函数
// 定义了x和y参数为字符串类型,以及定义了返回值是字符串类型
function add(x: string, y: string): string {
return x + y
}
console.log(add("20", "20"));
// 函数表达式,匿名函数
const add2 = function (x: number, y: number): number {
return x + y
}
console.log(add2(10, 20));
// 函数的完整写法
// 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));
})()
参数:可选参数,默认参数,动态参数
// 可选参数
// 默认参数
(() => {
// 定义一个函数:传入姓氏和名字,可以到完整名字
// 需求:如果不传入参数,默认返回姓氏
// 需求:只传入姓氏,返回姓氏
// 需求:传入姓氏和名字,返回完整名字
const getFullName = function (firstName: string = '李', lastName?: string): string {
// 判断是否传入了姓氏d
if (lastName) {
return firstName + '_' + lastName
}
return firstName
}
// 函数调用
console.log(getFullName('赵', '子龙'));
})()
// 动态参数:传入的参数可以是任意个
(() => {
function info(name: string, ...args: string[]) {
console.log(name, args);
}
info('必选参数', '动态传入的参数1', '动态传入的参数2', '动态传入的参数3', '动态传入的参数4')
})()
函数重载
// 函数重载:函数名字相同,函数参数及个数不同
// 作用:
(() => {
// 需求: 我们有一个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('祝福', '平安'));
console.log(add(1, 2));
// 用户传入非法参数,ts应该提示错误信息,可以使用函数重载
// console.log(add('1', 22));
})()
泛型:泛型的定义以及使用,一个函数多个泛型参数,泛型接口,泛型类
// 泛型:在定义函数、接口、类的时候不能预先确定 要使用的数据类型,而是使用函数、接口、类的时候才能确定数据的类型
(() => {
// 需求:定义一个函数,传入两个参数,第一个参数是数据,第二个参数是数量,函数的作用:根据数量,产生对应个数的数据,存放在一个数组中
// 定义一个函数
function getArr1(val: number, count: number): number[] {
// 根据数据和数量产生一个数组
const arr: number[] = []
for (let i = 0; i < count; i++) {
arr.push(val)
}
return arr
}
//做法1: 传入都是数字类型
// const arr1 = getArr1(100.131, 3)
// console.log(arr1);
// console.log(arr1[0].toFixed(2));
// 定义一个函数
function getArr2(val: string, count: number): string[] {
// 根据数据和数量产生一个数组
const arr: string[] = []
for (let i = 0; i < count; i++) {
arr.push(val)
}
return arr
}
// 做法2: 传入都是字符串类型
// const arr2 = getArr2("aaaa", 3)
// console.log(arr2);
// 定义一个函数:参数使用泛型
function getArr3<T>(val: T, count: number): T[] {
// 根据数据和数量产生一个数组
const arr: T[] = []
for (let i = 0; i < count; i++) {
arr.push(val)
}
return arr
}
const arr3 = getArr3<string>("aaaa", 3)
console.log(arr3);
console.log(arr3[0].split(''));
const arr4 = getArr3<number>(200, 3)
console.log(arr4);
console.log(arr4[0].toFixed(2));
// //做法3: 传入都是任意类型ddd
// const arr3 = getArr3(111, 3)
// console.log(arr3);
// console.log(arr3[0].toFixed(2));
})()
// 多个泛型参数的函数,函数中有多个泛型的参数
(() => {
function getMsg<K, V>(val1: K, val2: V): [K, V] {
return [val1, val2]
}
const arr1 = getMsg<string, number>('tony', 123456)
console.log(arr1[0].split(''), arr1[1].toFixed(2));
})()
// 泛型接口:在定义接口时,为接口中的属性或者方法定义泛型类型,在使用接口时,在指定具体的泛型类型
// 需求:定义一个类,用来存储用户的相关信息(id,姓名,年龄)
(() => {
// 定义一个泛型接口
interface IbaseCRUD<T> {
// 动态传入T类型,并定义为T类型的数据data
data: T[]
// 动态传入T类型,并定义其add函数的参数类型为T类型, =>返回的值也为T类型
add: (t: T) => T
// 动态传入T类型,并定义getUserId函数参数类型为number类型,=>返回值为T类型
getById: (id: number) => void
}
// 定义一个用户信息类
class User {
id?: number // 用户ID ?代表可有可无
name: string // 用户姓名
age: number // 用户年龄
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
// 使用泛型接口
// 定义一个类,可以针对用户的信息对象进行增加及查询的操作
// CRUD ====>create remove undata delete
class UserCRUD implements IbaseCRUD<User> {
// 用来保存多个user类型的用户信息对象
data: User[] = []
//用来添加存储用户信息对象
add(user: User): User {
// 产生id
user = { ...user, id: Date.now() + Math.random() }
// 把用户信息对象添加data数组中
this.data.push(user)
return user
}
// 方法根据id查找指定的用户信息对象
getById(id: number): void {
this.data.find(item => item.id === id)
}
}
// 实例化添加用户信息对象的类UserCRUD
const userCRUD = new UserCRUD()
const { id } = userCRUD.add(new User('java', 1))
userCRUD.add(new User('pythone', 2))
userCRUD.add(new User('php', 3))
userCRUD.add(new User('javascript', 4))
console.log(userCRUD.data)
})()
// 泛型类
(() => {
// 定义一个类,类中属性值的类型不确定,方法中的参数及返回值也不确定
// 定义一个泛型类
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
}
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function (x, y) {
return x + y
}
let myGenericString = new GenericNumber<string>()
myGenericString.zeroValue = 'abc'
myGenericString.add = function (x, y) {
return x + y
}
console.log(myGenericString.add(myGenericString.zeroValue, 'test'))
console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))
})()