// // 定义string
// let str:string = '你好啊哈'
// // 定义boolean
// let flag:boolean = true
// // flag = 123 报错因为上方定义了此变量只能为boolean类型
// // 定义numbur
// let age:number = 18
// age = 18.1 // 在ts里面没有区分整形和浮点型
// // console.log(age)
// // 定义数组(有两种定义方法,定义时可以统一指定数组内元素的类型)
// let arr2:number[] = [1,2,3]
// let arr1:Array<string> = ['js','python'] // 使用泛型
// // 定义元组(元组属于数组的变种,编译成es5之后其实就是数组,区别就是元组可以按顺序自定义数组中每个元素的类型)
// let tuple1:[string,number] = ['python',123]
// // tuple1 = [123,'小明'] // 报错,因为没有按照声明的顺序
// // console.log(tuple1)
// // 定义枚举类型enum(默认使用元素的下标当做枚举的值,可以手动指定下标的起始位置,当然我们也可以手动指定内部元素对应的值而不使用下标)
// enum color1 {red,green,blue} // 使用默认的下标
// let red:color1 = color1.red
// console.log(red)
// enum color2 {red=100,green,blue} // 指定初始元素的下标
// let green = color2.green
// console.log(green)
// enum color3 {red,green=5,blue} // 此时red的值为默认值0 green为我们指定的5 blue则按照上一位的下标来决定此时应是6
// let blue:color3 = color3.blue
// console.log(blue)
// enum res {success=1,error=-1} // 不使用下标,而使用我们自己定义的值
// let f:res = res.error
// console.log(f)
// console.log(res.success)
// // 定义任意类型any(对于一些无法确定的类型比如DOM比如Object我们使用any)
// let no_name:any = 123
// no_name = 'python'
// no_name = false
// no_name = {}
// // let box1 = document.querySelector('.box1') // 虽然运行正常但是会提示警告
// // box1.style.color='red'
// let box1:any = document.querySelector('.box1') //
// box1.style.color='red'
// // 定义 null, undefined
// // let num:number // 这里只定义但是并没有赋值虽然正常运行但是下面会警告
// // console.log(num)
// // let num:undefined // 手动指定num的类型为undefined
// // console.log(num)
// let num:number | undefined // 为变量指定两个可能存在的类型
// console.log(num)
// let a:undefined
// // a=null // 报错
// a = undefined
// // let n:null // null类型不允许赋值
// let n:null | number
// n = 123
// let b:null
// // b = undefined //报错
// b = null
// // 定义void 无类型(通常用于定义某些方法或者函数无返回值的)
// let f1 = (age:number):void => {}
// f1(18)
// let f2 = function f2():undefined {} // 错误写法
// let f2 = function f2():string {return 123} // 返回值错误
// 定义never类型是其他类型(包括null和undefined)的子类型,代表从不会出现的值
// 这意味着,声明never的变量只能被never类型锁赋值
// let c:never
// c = (()=>{
// throw new Error('错误')
// })()
// // es5函数的定义
// function f3(){} // 传统函数
// let f4 = ()=>{} // 匿名函数
// // ts函数的定义
// function f5(name:string|number[],age:number):string{return 'hello'}
// let f6 = function(name:string|Array<number>,age:number):number{return 23}
// let f7 = (name:string|any,age:number):void=> {}
// // ts中的可选参数(如果有一些参数可传可不传则使用 ? 来设置可选参数, 注意!: 可选参数必须配置到参数的最后面)
// let f8 = (name:string,age?:number)=>{if(age){console.log(`${name}今年${age}岁了`)} else{console.log(`${name}的年龄保密`)}}
// f8('小明')
// // ts中的默认参数(用来给一些参数设置默认值)
// let f9 = (name:string,age:number=18):void=>{console.log(`${name},今年${age}岁了`)}
// f9('小明',12)
// f9('小芳')
// // ts中的收集参数
// let f10 = (name:string,age:number,...args:Array<number>):void=>{console.log(args)}
// f10('小明',18,1,2,3,4,5)
// // ts中的函数重载(当有重名的函数的时候,对传入的参数约束会进行合并) 注意!: 不能使用匿名函数, (当两个及以上同名的函数但是他们的参数不一样,这时候会出现函数重载现象) 类似python中的"单分派泛函数",但是ts这里有点脱裤子放屁的感觉,如果不想调用的时候传递其他类型的参数完全可以 使用 string|number 限制传入的和传出的类型即可
// function f11(name:string):string;
// function f11(age:number):string;
// function f11(_flag:any):any {
// if (typeof _flag == 'string'){
// return `我叫${_flag}`
// }
// return `我今年${_flag}岁`
// }
// // ts中的类
// class Student{
// name:string // 实例属性,会挂载到原型上
// constructor(name:string,age?:number){ // 构造函数,实例化类的时候触发的方法
// this.name = name
// }
// run():void{ // 实例方法,会挂载到原型上
// console.log(`调用了实例方法,我是${this.name}`)
// }
// getname():string{
// return this.name
// }
// setname(name:string):void{
// this.name = name
// }
// }
// let stu1 = new Student('小明',18)
// stu1.run()
// stu1.setname('张三')
// console.log(stu1.getname())
// // ts中的继承
// class stu extends Student{
// }
// let stu2 = new stu('李四',22)
// console.log(stu2.getname())
// stu2.setname('李四啊') // 修改了名字
// stu2.run()
// console.log('------ts中的继承与super------')
// // ts中的super, 子类如果重写构造函数,那么构造函数必须执行一次super
// // super可以当做函数使用也可以当做对象使用, 当做函数使用的时候代表了父类的构造函数,但是返回的是子类的实例
// // super当做对象使用的时候则指向了父类的原型对象
// class stu extends Student{
// constructor(name:string){
// // super(name)
// console.log(super(name)) // 当做函数调用时super返回的和子类实例是一样的
// console.log(this)
// this.name = `子类-${name}`
// console.log(super.getname == Student.prototype.getname) // 当做对象的时候,super则代表了父类的原型对象
// }
// run(){
// console.log(`调用了子类的方法: ${this.name}`)
// }
// }
// let stu3 = new stu('李四')
// console.log(stu3.getname())
// stu3.run()
// ts中的类修饰符(属性不加修饰符默认为公有)
// public: 公有, 在类,子类,实例 中都可以访问该属性或者方法(这里就不做演示了)
// protected: 受保护的,在类,子类中可以访问,无法被实例访问
// private: 私有, 只能在类本身访问, 无法在子类和实例中访问
// class Student{
// protected name:string
// private age:number|undefined
// constructor(name:string,age?:number){
// this.name = name
// this.age = age
// }
// run(){
// console.log(this.name)
// console.log(this.age)
// }
// }
// class Stu extends Student{
// run(){
// console.log(this.name) // 子类中在类中可以访问被保护的属性
// // console.log(this.age) // 私有属性访问直接报错了
// }
// }
// let stu1 = new Student('小花',19)
// // console.log(stu1.name) // 实例无法访问受保护的属性
// // console.log(stu1.age) // 私有属性无法访问
// stu1.run() // 无论是公有私有还有受保护在当前类的方法内部中都能访问
// let stu2 = new Stu('小明',22)
// stu2.run()
// // ts中的类方法静态方法和静态属性, 静态方法内无法访问实例属性,只能访问静态属性,静态方法只能类调用,实例无法调用
// class Student{
// public name:string
// static age:number = 19
// constructor(name:string){
// this.name = name
// }
// static run():void{
// console.log(`this is static a function`)
// // console.log(this.name) // 无法访问,因为在创建类的时候还没有实例化的属性
// console.log(Student.age)
// }
// say(){
// console.log(this.name)
// }
// }
// console.log(Student.age)
// Student.run()
// // ts多态(详见本博客Python版 http://152.69.196.199/index.php/archives/236.html )
// // ts抽象方法(详见本博客Python版 http://152.69.196.199/index.php/archives/234.html, 在ts中抽象类作为其他类的基类,不能被实例化,抽象类中的抽象方法不包含具体的实现,实现方法必须在派生类中,在ts中使用 abstract 抽象方法只能放在抽象类中)
// abstract class Animal{
// public name:string
// constructor(name:string){
// this.name = name
// }
// abstract eat():any;
// }
// class Dog extends Animal{
// eat(){
// console.log(`${this.name}在吃东西`)
// }
// }
// let dog = new Dog('小狗')
// dog.eat()
// ts中的接口(接口是一种规范的定义,定义了行为和动作规范,接口定义了某一批类所需要准守的规范,而不关系这些类或函数内部的状态数据,也不关心类中方法的细节)
// 为什么函数中有了类型约束还要搞接口? 概念不一样两者不会相互影响是独立的
// // 1. 自定义方法对json进行约束
// let f12 = function(jsonstr:{'lable':string,'age':number}):void{
// console.log(jsonstr.lable,jsonstr.age)
// }
// f12({'lable':'张三',age:19})
// // 2. 使用接口进行约束
// interface FullName{
// name:string;
// age?:number
// }
// let f13 = (jsonstr:FullName)=>{
// // 必须传入一个对象且有 name和age
// console.log(jsonstr.name,jsonstr.age)
// }
// f13({'name':'李四','age':18})
// // f13({'name':'李四','age':18,'gender':'man'}) // 如果内部的元素比约束条件多,则需要使用对象的方式传入函数中
// let obj = {'name':'李四','age':18,'gender':'man'}
// f13(obj)
// 函数类型接口(对方法传入的参数以及返回值进行约束)
// interface encrypt{
// (key:string,value:string):string
// }
// let md5:encrypt = (key:string,value:string):string=>{return `${key} + ${value}`}
// console.log(md5('hello','world'))
// 可索引接口
// 1. 数组的接口
// interface Arr{
// [index:number]:string
// }
// let arr1:Arr = ['小明','小花']
// console.log(arr1)
// 对象的接口
// interface obj{
// [index:string]:any
// }
// let stu:obj = {'namg':'张三','age':18}
// 类类型接口约束(对类进行的约束,和抽象类有点相似)
// interface Animal{
// name:string // 必须有name属性
// eat(str:string):void // 必须要有eat方法
// }
// class Dog implements Animal{
// name:string
// constructor(name:string){
// this.name = name
// }
// eat(str:string){
// console.log(`${this.name}在吃${str}`)
// }
// }
// let dog = new Dog('小狗')
// dog.eat('骨头')
// 类类型接口的继承
// interface Animal{
// eat():void
// }
// interface Person extends Animal{
// say():void
// }
// class P1{
// eat(){console.log('吃饭')}
// }
// class P2 extends P1 implements Person{
// say(){console.log('说话')}
// }
// let p = new P2
// p.eat()
// p.say()
// ts中的泛型(一个组件可以支持任意数据类型,提高复用性,以及对不特定数据类型的支持)
// 1. 不使用泛型
// function f4(value:string):string{ // 这个函数只能传入和返回string类型的数据(如果需要返回不同类型则需要重新定义一个新的函数,造成代码冗余)
// return ``
// }
// function f5(value:number):number{ // 这个函数只能传入和返回number类型的数据(如果需要返回不同类型则需要重新定义一个新的函数,造成代码冗余)
// return 0
// }
// function f6(value:any):any{} // 使用 any 类型这样虽然可以返回任意类型,但是却放弃了 类型检查
// 2. 大写的T表示泛型,具体是什么类型则是在调用这个方法的时候决定的
// function f7<T>(value:T):T{
// return value
// }
// console.log(f7<string>('小明')) // 在函数调用的时候指定传入的数据类型
// console.log(f7<number>(123))
// // 3. 定义泛型接口1(在函数调用时指定参数类型)
// interface say {
// <T>(value:T):T
// }
// let say_hello:say = <T>(value:T):T => {return value}
// console.log(say_hello<string>('123'))
// console.log(say_hello<number>(2233))
// // console.log(say_hello<number>('abcd')) // 错误写法
// // 3.1 定义泛型接口2(创建函数时指定该函数的泛型接口,让函数只能使用指定类型的参数)
// interface say <T>{ // 泛型接口
// (value:T):T
// }
// // let say_hello:say<string> = <T>(value:T):T=> value; // 定义一个指定泛型接口的函数
// let say_hello:say<string> = (value)=> value; // 定义一个指定泛型接口的函数
// say_hello('abc')
// // say_hello(123) // 错误写法
// 3.2 泛型类(在实例化的时候指定类中数据使用的类型)
// 普通的类写法
// class math{
// public li:string[] = []
// append(value:string):void{
// this.li.push(value)
// }
// min():string{
// let flag:string = this.li[0]
// for(let i of this.li){
// if(flag > i) flag = i
// }
// return flag
// }
// }
// let m = new math
// m.append('b')
// m.append('c')
// m.append('a')
// console.log(m.min())
// 泛型类写法(可以在实例化的时候指定所要使用的类型)
// class math2<T>{
// public li:T[] = []
// append(value:T):void{
// this.li.push(value)
// }
// min():T{
// let flag:T = this.li[0]
// for(let i of this.li){
// if(flag > i) flag = i
// }
// return flag
// }
// }
// let m2 = new math2<number>()
// m2.append('b') // 错误的写法
// m2.append('c')
// m2.append('a')
// console.log(m2.min())
// // 自定义普通类
// class User{ // 定义一个用户类
// username:string
// password:string
// age?:number
// constructor(username:string,password:string,age?:number){
// this.username = username
// this.password = password
// this.age = age
// }
// }
// class Article{ // 定义一个文章类
// title:string
// info:string
// constructor(title:string,info:string,){
// this.title = title
// this.info = info
// }
// }
// // 增加管理用户类的mysql工具
// class MysqlDB{
// add(user:User):boolean{
// console.log(user)
// return true
// }
// }
// let user1 = new User('张三','asd123')
// let mysql = new MysqlDB() // 这个实例化的类只能对User类使用add,因为add的类型检查就是User类,如果再增加一个 文章类, 那么这个实例化的mysql类就没用了
// mysql.add(user1)
// // 增加管理文章类的 mysql工具
// let article1 = new Article('水浒传','四大名著之一')
// // mysql.add(article1) // 错误写法,如果想增加管理article类的功能需要重新写MysqlDB的类
// class MysqlDB_Art{
// add(article:Article):boolean{
// console.log(article)
// return true
// }
// }
// let mysql_art = new MysqlDB_Art
// mysql_art.add(article1)
// 自定义泛型类(可以在类实例化的时候指定实例化后的类可以操作的数据类型)
// class Article{ // 定义一个文章类
// title:string
// info:string
// constructor(title:string,info:string,){
// this.title = title
// this.info = info
// }
// }
// class User{ // 定义一个用户类
// username:string
// password:string
// age?:number
// constructor(username:string,password:string,age?:number){
// this.username = username
// this.password = password
// this.age = age
// }
// }
// class Mysql_utils<T>{ // 自定义数据库泛型类在实例化的时候可以指定改实例化的sql类操作的数据类型
// add(flag:T):boolean{
// console.log(flag)
// return true
// }
// update(flag:T,title:string):void{
// console.log(title, flag)
// }
// }
// let user1 = new User('张三','asd123')
// let art1 = new Article('水浒传','四大名著之一')
// let Sql_user = new Mysql_utils<User>()
// let Sql_art = new Mysql_utils<Article>()
// Sql_art.add(art1)
// Sql_user.add(user1)
// 定义一个BooksCreate类模拟ORM
// class BooksCreate{
// title:string
// info:string
// constructor(data:{title:string,info:string}){ // 对形参设置接口约束
// this.title = data.title
// this.info = data.info
// }
// }
// let book_db = new Mysql_utils<BooksCreate>()
// let book1 = new BooksCreate({'title':'水浒传','info':'四大名著之一'})
// book_db.add(book1)
// book_db.update(book1,'西游记')
// 自定义一个数据库类来分别对不同的数据库进行操作
// interface dbface<T>{ // 定义接口约束
// add(info:T):boolean
// update(info:T,id:number):boolean
// get(id:number):any[]
// delete(id:number):boolean
// }
// // 定义一个操作mysql数据库的类
// class MysqlDB<T> implements dbface<T>{
// add(info: T): boolean {
// console.log(`增加成功`,info)
// return true
// }
// update(info: T, id: number): boolean {
// throw new Error("Method not implemented.");
// }
// get(id: number): T[] {
// // 根据id找到用户,返回带用户逇数组
// let li:T[] = []
// return li
// }
// delete(id: number): boolean {
// throw new Error("Method not implemented.");
// }
// }
// class MongoDB<T> implements dbface<T>{
// add(info: T): boolean {
// throw new Error("Method not implemented.");
// }
// update(info: T, id: number): boolean {
// throw new Error("Method not implemented.");
// }
// get(id: number): any[] {
// throw new Error("Method not implemented.");
// }
// delete(id: number): boolean {
// throw new Error("Method not implemented.");
// }
// }
// class User{ // 自定义一个用户类
// name:string
// password:string
// constructor(data:{name:string,password:string}){
// this.name = data.name
// this.password = data.password
// }
// }
// let u1 = new User({name:'张三',password:'asd'})
// let mysql = new MysqlDB<User>()
// mysql.add(u1)
// mysql.get(123)
// ts中的导入模块(需要在终端中使用node命令运行编译后的js文件,真tm的拉垮,不能使用 : 起别名,需要使用 as 关键字起别名)
// import {get_data as get,url} from './db'
// console.log(get)
// console.log(url)
// // ts中的命名空间(注意命名空间里面的变量需要暴露出来才能使用)
// namespace A {
// export let flag:string = '张三'
// }
// namespace B {
// export let flag:string = '李四'
// }
// console.log(B.flag)
// ts中的装饰器(类装饰器, 属性装饰器, 方法装饰器, 参数装饰器)
// // 普通装饰器(如果装饰器函数中没有返回则默认返回传进来的参数)
// let log_utils = (parms:any):any=>{
// parms.prototype.url = '152.69.196.199' // 给传进来的对象的原型对象上增加属性
// console.log(parms)
// return 123
// }
// @log_utils
// class HttpClint{
// constructor(){
// }
// get_data():void{
// console.log('获取数据')
// }
// }
// console.log(HttpClint)
// 参数装饰器(装饰类时:内部函数接收一个参数,类的构造函数)
// let log_utils = (parms:any):any=>{
// let warpper = function(target:any){ // 类的构造函数
// console.log(parms)
// console.log(target)
// target.prototype.url = parms
// }
// return warpper
// }
// @log_utils('www.baidu.com')
// class HttpClint{
// constructor(){
// }
// get_data():void{
// console.log('获取数据')
// }
// }
// let http = new HttpClint
// console.log(http.constructor)
// // 类装饰器修改当前类的构造函数(类装饰器表达式会在运行时当做函数调用,类的构造函数作为唯一参数)
// // 装饰器内对类重载
// let log_utils = function(target:any):any{
// return class extends target {
// url = '修改后的数据'
// }
// }
// @log_utils
// class HttpClint2{
// public url?:string
// constructor(){
// this.url = '我是构造函数中的url'
// }
// get_data():void{
// console.log(this.url)
// }
// }
// let http2 = new HttpClint2()
// http2.get_data()
// 装饰器传参,类属性装饰器()
// let log_property = function(parmas:any,){
// return function(target:any,attribute:any){ // 修改属性时:内部函数接收两个参数,对于静态成员则是构造函数对于实例成员则是原型对象, 属性名称
// console.log(parmas)
// console.log(target)
// console.log(attribute)
// target[attribute] = parmas
// }
// }
// class HttpClint3{
// @log_property('www.baidu.com')
// public url?:string
// @log_property('www.qq.com')
// static url2?:string
// constructor(){
// }
// get_data():void{
// console.log(this.url)
// }
// }
// let http = new HttpClint3
// http.get_data()
// 类方法装饰器(会被应用到方法的属性描述符上,用来监听修改或者替换方法的定义,方法装饰器传入三个参数, 对于静态成员则是构造函数对于实例成员则是原型对象,成员的名字,成员的属性描述符)
// let log_method = function(parmas:any){
// return function(target:any,method_name:any,desc:any){
// console.log(target)
// console.log(method_name)
// console.log(desc)
// // 修改方法
// let _method:any = desc.value
// desc.value = function(...args:any){
// for(let i of args){
// console.log(i)
// }
// console.log('运行原方法之前自定义一些代码运行')
// _method.apply(this,args)
// }
// // 增加方法
// target.say = function(){
// console.log('hello')
// }
// }
// }
// class HttpClint3{
// constructor(){
// }
// @log_method('123')
// public say_hi(...args:any):void{
// console.log('hi,这是原生方法传进来的参数有: ',args)
// }
// @log_method('123')
// static say_hello():void{
// }
// }
// let http:any = new HttpClint3
// http.say()
// HttpClint3.say()
// // 调用被修改后的方法
// http.say_hi(1,2,3,4,5)
// 方法的参数装饰器(传入三个参数,1.对于静态成员是构造函数,对于实例成员是原型对象, 2.方法的名字, 3.参数在方法的所有的参数列表中的索引)
let logProams = function (params:any){
return function(target:any,method_name:any,idx:any){
console.log(params)
console.log(target)
console.log(method_name)
console.log(idx)
}
}
class Animal{
say(@logProams('hi') str:any){
console.log(str)
}
}
let dog = new Animal
dog.say('hello')
// 装饰器的执行顺序
// 属性装饰器->方法装饰器->方法参数装饰器->类装饰器
// 如果有多个装饰器则从右到左,从下到上依次执行(上电梯大法)