文章目录
- 启动自动监视,编译代码
- ts中的类型编写
- ts中的类,接口等相关内容
- es5中类,继承相关内容
- ts的类,接口相关内容
- ts泛型(泛型定义,泛型函数,泛型类,泛型接口)
- 通过ts泛型模拟不同数据库使用
- ts结构之命名空间,模块
- 初识命名空间概念以及namespace,export关键字
- 命名空间模块化
- ts之装饰器
- 开启ES7标准
- 属性装饰器
- 方法装饰器
- 方法参数装饰器
- 装饰器执行顺序
启动自动监视,编译代码
在D盘创建一个tsProject目录作为Typescript学习目录。
在vscode打开该文件夹,使用命令行输入:tsc --init
初始化文件夹后,会生成自动tsconfig.json,默认是没有这个文件的。
新键一个index.ts,打开注释修改自动编译路径,"outDir":"./js"
编写ts文件,写入let str:string="hello ts"
然后保存
在终端处选择运行任务,然后选typescript,然后选择监视
它就会监视文件,自动编译文件到指定目录输出,我们在index.ts加一行代码保存验证一下
老版本的路径有点不一样,我们也可以直接使用我们控制台输出的那个命令,一样的效果,监视的前提是必须已经初始化了。
监视指令为:tsc -p 路径\tsconfig.json --watch
如和本文一致路径可直接使用以下指令开启
tsc -p d:\tsProject\tsconfig.json --watch
接下来现在文件夹创建一个index.html
然后引入我们js目录下的js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<div id="box">
box
</div>
</body>
</html>
<script src="js/index.js"></script>
ts中的类型编写
接下来就是熟悉ts中各种类型的编写:(继续在我们的index.ts文件中编写内容)
let str: string = "hello,ts"
let str1: string = "hello,typescript"
//布尔类型(boolean) true false
var flag: boolean = true
//数字类型(number)
var a: number = 123
console.log(a)
//a="123" 错误写法,因为已经指定类型
a = 1.23 //不报错,Number类型包括整型和浮点型
console.log(a)
//数组类型(array) ts中定义数组有两种方式
//es5中,写法,什么类型都可以放在一个数组中
//var array=[12,true,"js"]
//1.ts中,第一种定义数组的方法
let arr1: string[] = ["java", "c#"]
console.log(arr1)
//2.ts中,第二种定义数组的方法
//如果要写字符串就是把<number>的number换成string就可以
let arr2: Array<number> = [1, 12, 12.3]
console.log(arr2)
//3.ts中,第三种定义数组的方法(any放任意类型)
let arr3: any[] = ["str", 12, false, arr1]
console.log(arr3)
//元组类型(tuple) 属于数组的一种
//等式两边的类型必须一致
let arr: [string, number, boolean] = ["ts", 3.14, false]
console.log(arr)
//枚举类型(enum)
/*
enum 枚举名{
标识符[=整数常量]
标识符[=整数常量]
标识符[=整数常量]
...
标识符[=整数常量]
};
常用场景 pay_status 0 未支付 1 支付 2交易成功
flag 1表示true 0表示false
*/
enum Flag { success = 1, error = 0 }
var f: Flag = Flag.success
console.log(f)
enum color { red = 1, green = 2, blue = 3 }
enum Err { 'undefined' = -1, 'null' = -2, 'success' = 1 }
var e: Err = 1
console.log(e)
//任意类型(any)
let num: any = 12
num = "str"
num = true
num = [123, 12]
//任意类型的用处,可以不出现警告
var oBox: any = document.getElementById('box');
oBox.style.color = 'red';
//null和undefined 其他(never类型)数据类型的子类型
/*
var variable:number; //没初始化赋值
console.log(variable); //报错
var variable:undefined;
console.log(variable); //不报错,输出:undefined,是正确的
var variable:null;
variable=null;
*/
//类型为未定义或者是数字类型或者null类型
var variable: number | undefined | null;
console.log(variable)
//void类型,主要用于定义方法,如果方法没有返回值就使用冒号void
function run(): void {
console.log('run')
}//即为方法没有返回任何类型
run();
//never类型,重来不会出现的类型
// var b:never;
// b=(()=>{
// throw new Error('错误');
// })()//先注释了,不然下面的代码使用函数调用有问题
//3.1 函数定义
//es5定义函数的方法
//函数声明法
function fun() {
return 'fun';
}
var fun1 = function () {
return 'fun';
}
//ts中定义函数
//函数声明法
function fun2(): string {
return 'fun';
}
/*
function fun2():string{
return '123';
}//错误写法,函数类型和返回值类型必须一致
*/
//匿名函数
var fun3 = function (): number {
return 123;
}
alert(fun3());//调用方法
//ts中定义方法传参
//返回值使用飘符号$括号属性飘符号取值
//看代码颜色可区分,注意和单引号区分
function getinfo(name: string, age: number): string {
return `${name} --- ${age}`;
}
//传参也必须是和函数方法参数类型一致,不一致会有编译问题
alert(getinfo('zhangsan', 20));
//匿名函数
var getinfo1 = function (name: string, age: number): string {
return `${name} --- ${age}`;
}
alert(getinfo1('lisi', 19));
//没有返回值的方法
function noreturn(): void { }
noreturn();
//3.2方法可选参数
//es5里面方法的实参和形参可以不一样,但是ts必须一致
//如果不一样需要配置可选参数
function getinfo2(name: string, age?: number, sex?: string): string {
if (age) {
return `${name} --- ${age}`;
} else {
return `${name} ---年龄保密`;
}
}
alert(getinfo2('wangwu'));
//可选参数以参数?:类型的形式存在,而且必须在参数的末尾配置,可配置多个可选参数
//3.3默认参数 类似可选参数
//es5里面没法设置参数,es6和ts中都可以设置默认参数
function getInfo(name: string, age = 25): string {
if (age) {
return `${name} --- ${age}`;
} else {
return `${name} ---年龄保密`
}
}
//没有传参,默认就会有25出现
alert(getInfo('张三'));
//3.4剩余参数
/*
function sum(a:number,b:number,c:number){
return a+b+c;
}
*/
//三点运算符 接收形参传过来的值
function sum(...result: number[]): number {
var sum = 0;
for (var i = 0; i < result.length; i++) {
sum += result[i];
}
return sum;
}
alert(sum(1, 2, 3));
//3.5 ts函数的重载
//java中方法的重载,重载是指的是两个或者两个以上的同名函数,但它们的参数不一样,这时会出现函数重载的情况
//typescript中的重载,通过为统一函数提供多个函数类型定义来试下多种功能的目的
//ts为了兼容es5以及es6重载的写法和java中有区别
//es5中出现同名方法,下面的会替换上面的方法
/*
function css(config){}
function css(config,value){}
*/
//ts中的重载
function getReload(name: string): string;
function getReload(age: number): number;
function getReload(str: any): any {
if (typeof str === 'string') {
return '我叫: ' + str;
} else {
return '我的年龄是' + str;
}
}
alert(getReload('李四'));//传的必须要已经声明了的方法,如这个不能传boolea,因为没有声明
//alert(getReload(true));//在此处算错误写法
function getReload1(name: string): string;
function getReload1(name: string, age: number): string;
function getReload1(name: any, age?: any): string {
if (age) {
return '我叫: ' + name + '我的年龄是' + age;
} else {
return '我叫: ' + name;
}
}
alert(getReload1('王五', 15));
alert(getReload1('王五'));
//alert(getReload1('王五',true))//错误,由于未定义有boolean类型的形参
//3.6 箭头函数 es6
//箭头函数中,this指向上下文
// setTimeout(function(){
// alert('timeout')
// },1000)//es5的写法
setTimeout(() => {
alert('timeout')
}, 1000)
ts中的类,接口等相关内容
es5中类,继承相关内容
1.先创建一个html,可利用vscode快速生成模板
步骤:创建一个名为es5创建对象 继承html后缀文件,创建后在文本内容里输入:/
然后按下Tab键即可。
可参考我另外一篇博客:
然后就是相关联系的代码啦!亮代码啦
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
//es5里面的类
//1.最简单的类,以前没class,所有类在以前是使用function关键字来修饰,从而达到效果
// function Person(){
// this.name='张三';
// this.age=20
// }
// var p=new Person();
// alert(p.name);
//2.构造函数和原型链里面增加方法
/*
function Person(){
this.name='张三';//属性
this.age=20;
this.run=function(){//实例方法
alert(this.name+'在运动')
}
}
Person.getInfo=function(){
alert('我是静态方法');
}
//原型链上面的属性会被多个是咯共享 构造函数不会
Person.prototype.sex='男';
Person.prototype.work=function(){
alert(this.name+'在工作')
}
var p=new Person();
//alert(p.name);
p.run();
p.work();
Person.getInfo();
*/
//4.es5里面的继承
// function Person(){
// this.name='张三';//属性
// this.age=20;
// this.run=function(){//实例方法
// alert(this.name+'在运动')
// }
// }
// Person.getInfo=function(){
// alert('我是静态方法');
// }
// //原型链上面的属性会被多个是咯共享 构造函数不会
// Person.prototype.sex='男';
// Person.prototype.work=function(){
// alert(this.name+'在工作')
// }
// var p=new Person();
// //alert(p.name);
// p.run();
// p.work();
// Person.getInfo();
// //Web类 继承Person类 原型链对象冒充的组合继承模式
// function Web(){
// Person.call(this);//对象冒充实现继承
// }
// var w=new Web();
// //w.run(); //对象冒充可以继承构造函数里面的属性和方法
// //报错
// w.work();//对象冒充可以继承构造函数里面的属性和方法 单没法继承原型连上面的属性和方法
//5.web类 继承Person类 原型链+对象冒充的组合继承模式
// function Person(){
// this.name='张三';//属性
// this.age=20;
// this.run=function(){//实例方法
// alert(this.name+'在运动')
// }
// }
// //原型链上面的属性会被多个是咯共享 构造函数不会
// Person.prototype.sex='男';
// Person.prototype.work=function(){
// alert(this.name+'在工作')
// }
// //Web类 继承Person类 原型链+对象冒充的组合继承模式
// function Web(){
// }
// Web.prototype=new Person(); //原型链实现基础
// var w=new Web();
// w.run();
// w.work();
// //原型链继承既可以继承原型链上的方法,也可以继承构造函数上的方法
//6.原型链实现继承的 问题?
// function Person(name,age){
// this.name=name;//属性
// this.age=age;
// this.run=function(){//实例方法
// alert(this.name+'在运动');
// }
// }
// Person.prototype.sex='男';
// Person.prototype.work=function(){
// alert(this.name+'在工作');
// }
// //var p=new Person('李四',20);
// //p.run();
// function Web(name,age){
// }
// //使用Web继承
// Web.prototype=new Person();
// var w=new Web('赵四',20);//实例化字类的时候没法给父类传参
// w.run();//调用run方法不是赵四在运动而是undefined在运动
//7.原型链+构造函数的组合继承模式
function Person(name,age){
this.name=name;//属性
this.age=age;
this.run=function(){//实例方法
alert(this.name+'在运动');
}
}
Person.prototype.sex='男';
Person.prototype.work=function(){
alert(this.name+'在工作');
}
//var p=new Person('李四',20);
//p.run();
function Web(name,age){
Person.call(this,name,age)
}
//使用Web继承
Web.prototype=Person.prototype;
var w=new Web('王五',20);//实例化字类的时候没法给父类传参
w.work();
w.run();
</script>
</html>
这里总结一句就是冒充对象实际上就是利用改变this的指向来完成继承
ts的类,接口相关内容
//1.ts中类的定义
/*
es5中:
function Person(name){
this.name=name
this.run=function(){
console.log(this.name)
}
}
var p=new Person('张三');
p.run();
*/
//ts写法
// class Person{
// name:string ; //属性 前面省略了public关键词
// constructor(n:string){ //构造函数 实例化类的时候触发的方法
// this.name=n;
// }
// run():void{
// alert(this.name)
// }
// }
// var p=new Person('张三');
// p.run()
// class Person {
// name: string; //属性 前面省略了public关键词
// constructor(n: string) { //构造函数 实例化类的时候触发的方法
// this.name = n;
// }
// run(): void {
// alert(this.name)
// }
// }
// var p = new Person('张三');
// p.run()
/*
class Person{
name:string;
constructor(name:string){
this.name=name
}
getName():string{
return this.name;
}
setName(name:string):void{
this.name=name
}
}
var p=new Person('法外狂徒');
alert(p.getName());
p.setName('张三');
alert(p.getName());
*/
//2.ts中实现继承 extends,super
// class Person {
// name:string;//没写表示共有
// constructor(name:string) {
// this.name=name;
// }
// run():string{
// return `${this.name}在运动`;
// }
// }
// //var p=new Person('马六');
// //alert(p.run());
// //展示继承和多态
// class Web extends Person{
// constructor(name:string){
// super(name);
// }
// run():string{
// return `${this.name}在运动,走的子类方法`;
// }
// work():string{
// return `${this.name} 在工作`;
// }
// }
// var w=new Web('小七');
// alert(w.run());
// alert(w.work());
//3 类里面的修饰符 ts中定义属性的时候给我们提供了 三种修饰符
/*
public :共有 在类里面,子类,类外都可以访问
protected:保护类型 在类里面,子类里面可以访问,在类外部没法访问
private:私有 在类里面可以访问,字类。类外部都没法访问
属性不加修饰符,默认为public
*/
//共有public
// class Person {
// name:string;//没写表示共有
// constructor(name:string) {
// this.name=name;
// }
// run():string{
// return `${this.name}在运动`;
// }
// }
// var p=new Person('hehe');
// alert(p.name);//打印出hehe
//保护protected
class Person {
protected name:string;
constructor(name:string) {
this.name=name;
}
run():string{
return `${this.name}在运动`;
}
}
class Web extends Person{
constructor(name:string){
super(name);
}
work(){
alert(`${this.name}在工作`);
}
}
var w=new Web('小四');
//var p=new Person('小五');
//p.name //报错在protected无法访问,这是外部直接调用的写法
w.work();
alert(w.run());
//private :私有 它类里面可以访问,字类,类外部都没法访问
//name被Private修饰,子类调用${this.name}无法编译通过
//调用自己则可以
class Person1 {
private name:string;
constructor(name:string) {
this.name=name;
}
run():string{
return `${this.name}在运动`;
}
}
var p1=new Person1('p1');
alert(p1.run());//打印p1在运动
//4.静态属性 静态方法
//es5里面调用静态写法
// function Person(){
// this.run1=function(){}
// }
// Person.name='嘻嘻';
// Person.run2=function(){//静态方法
// }
// var p=new Person();
// Person.run2();//静态调用
//静态调用在jq里挺多应用的,有兴趣可以去了解一下
class Per{
public name:string
static sex:string='女';
constructor(name:string){
this.name=name;
}
run(){ //实例方法
alert(`${this.name}在运动`);
}
work(){
alert(`${this.name}在工作`);
}
static print(){ //静态方法,静态只能调用静态
alert('print方法'+Per.sex);
}
}
Per.print();
alert(Per.sex);
//多态:父类定义一个方法不去实现,让继承它的子类去实现,每一个子类都有不同的表现
//多态属于继承
// 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 dog=new Dog('狗');
// var cat=new Cat('猫');
// alert(cat.eat());
//typescript中的抽象类,它是提供其他类继承的基类,不能被直接实现
//abstract关键字定义抽象类和抽象方法
//抽象类中的抽象方法不包含具体实现实现必须在派生类中实现,不能直接new
// abstract class Animal {
// name:string;
// constructor(name:string) {
// this.name=name
// }
// abstract eat():any;
// }
// class Dog extends Animal{
// constructor(name:string){
// super(name);
// }
// eat() {
// //throw new Error("Method not implemented.")
// console.log(this.name+'吃粮食');
// }
// }
// var d=new Dog('旺财');
// d.eat();
// abstract class Bird extends Animal{
// constructor(name:string){
// super(name)
// }
// abstract eat():any;
// }
//接口=》定义标准规范限制,灵活,扩展性更高
/*
属性类型接口
函数类型接口
可索引类型接口
类类型接口
接口扩展
*/
//1.属性接口 对json的结果
//ts中定义方法
// function printLabel():void{
// console.log('printLabel');
// }
// printLabel();
//ts中定义方法传入参数
// function printLabel(label:string):void{
// console.log('printLabel');
// }
// //printLabel(123);//错误写法
// printLabel('456');
//ts中自定义方法参入参数对json进行约束
// function printLabel(labelInfo:{label:string}):void{
// console.log('printLable');
// }
// //printLabel('haha');//错误写法
// //printLabel({name:'zhangsan'}) //错误写法
// printLabel({label:'zhangsan'});
//对批量方法传入参数进行约束
//传入对象的约束 属性接口
interface FullName{
firstName:string; //注意分号结束
secondName:string;
}
function printName(name:FullName){
//必须传入对象 firstName,secondName
console.log(name.firstName+'--'+name.secondName);
}
var obj={
age:15,
firstName:'wang',
secondName:'wu'
}
printName(obj);
function printInfo(info:FullName){
//必须传入对象 firstName,secondName
console.log(info.firstName+'--'+info.secondName);
}
printInfo({
firstName:'xiao',
secondName:'liu'
})
//接口,可选属性,一行是在属性后面冒号前面加问号
interface AllName{
firstName:string; //注意分号结束
secondName?:string;
}
function getName(name:AllName){
console.log(name);
}
getName({
firstName:'仨'
})
//以属性类型接口,封装ajax写法
interface Config{
type:string;
url:string;
data?:string
dataType:string
}
//原生js封装的ajax,不兼容ie6
// function ajax(config:Config){
// var xhr=new XMLHttpRequest();
// xhr.open(config.type,config.url,true);
// xhr.send(config.data);
// xhr.onreadystatechange=function(){
// if (xhr.readyState==4 && xhr.status==200) {
// console.log('chenggong');
// if (config.dataType=='json') {
// console.log(JSON.parse(xhr.responseText));
// } else {
// console.log(xhr.responseText)
// }
// }
// }
// }
// ajax({
// type:'get',
// url:'http://www.baidu.com',
// dataType:'json'
// })
//函数类型接口:对方法传入的参数 以及返回值进行约束 可以做批量约束
//实现加密类型的函数接口
interface encrypt{
(key:string,value:string):string
}
var md5:encrypt=function(key:string,value:string):string{
//省略md5算法代码
//模拟操作
return key+value;
}
console.log(md5('name','zhangsan'));
var sha1:encrypt=function(key:string,value:string):string{
//省略sha1算法代码
//模拟操作
return key+'---'+value;
}
console.log(sha1('name','lisi'));
//可索引接口,数组,对象的约束 (不常用)
//ts定义数组的方式
// var array:number[]=[123,456];
// var array1:Array<string>=['12','34'];
//对数组的约束 即可索引约束
// interface UserArr{
// [index:number]:string
// }
// var array:UserArr=['123','3245'];
// console.log(array[0]);
//对对象约束 不常用
// interface UserObj{
// [index:string]:string
// }
// var arrObj:UserObj={name:'zhangsan'};
//类类型接口:对类的约束 和抽象类有点相似
// 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();
// class Cat implements Animal{
// name:string;
// constructor(name:string){
// this.name=name;
// }
// eat(food:string){
// console.log(this.name+food)
// }
// }
// var c=new Cat('小花');
// c.eat('老吃鼠');
//接口扩展,接口可以继承接口
// interface Animal{
// eat():void;
// }
// interface Person2 extends Animal{
// work():void;
// }
// class Web2 implements Person2{
// name:string
// constructor(name:string){
// this.name=name;
// }
// eat(){
// console.log(this.name+'喜欢吃饭')
// }
// work(){
// console.log(this.name+'的工作是敲代码')
// }
// }
// var web2=new Web2('xiaolei');
// web2.work();
interface Animal{
eat():void;
}
interface Person2 extends Animal{
work():void;
}
class Programmer{
name:string;
constructor(name:string){
this.name=name;
}
coding(code:string){
console.log(this.name+code);
}
}
class Web2 extends Programmer implements Person2{
public name:string
constructor(name:string){
super(name);
this.name=name;
}
eat(){
console.log(this.name+'喜欢吃饭')
}
work(){
console.log(this.name+'的工作是敲代码')
}
}
var web2=new Web2('xiaolei');
web2.work();
web2.coding('在写ts代码');
ts泛型(泛型定义,泛型函数,泛型类,泛型接口)
/*
泛型就是解决 类 接口 方法的复用性 以及对不特定数据类型的支持
*/
// function getData(value:string):string{
// return value;
// }
//T表示泛型,具体什么类型是调用这个方法的时候决定的
// function getData<T>(value:T):T{
// return value;
// }
// getData<number>(123);
// getData<string>('1231');
// getData<boolean>(true);
// //getData<number>('123');//错误写法
//泛型类,比如有一个最小堆算法,需要同时支持返回数字和字符串两种类型。 通过类的泛型来实现
// class MinClass{
// public list:number[]=[];
// add(num:number){
// this.list.push(num);
// }
// min():number{
// var minNum=this.list[0];
// for(var i=0;i<this.list.length;i++){
// if(minNum>this.list[i]){
// minNum=this.list[i];
// }
// }
// return minNum;
// }
// }
// var m=new MinClass();
// m.add(3);
// m.add(2);
// m.add(15);
//上面是只返回数字,下面演示泛型改良版,同时支持数字和字符串,根据传参返回
//类的泛型
class MinClass<T>{
public list:T[]=[];
add(value:T):void{
this.list.push(value)
}
min():T{
var minNum=this.list[0];
for(var i=0;i<this.list.length;i++){
if(minNum>this.list[i]){
minNum=this.list[i];
}
}
return minNum;
}
}
var m1=new MinClass<number>();//实例化类,并且指定了类的代表的类型是number
m1.add(3);
m1.add(2);
m1.add(15);
alert(m1.min());
var m2=new MinClass<string>();//实例字符串,根据Asic码(忘记是不是这样打了哈哈)
m2.add('a');
m2.add('s');
m2.add('das');
alert(m2.min());
//ts中的泛型
// 泛型的定义
// 泛型函数
// 泛型类
// 泛型接口
//函数型接口
// interface ConfigFn{
// (value1:string,value2:string):string;
// }
// var setData:ConfigFn=function(value1:string,value2:string):string{
// return value1+value2;
// }
// setData('name','zhangsan');
//泛型接口 第一种
// interface ConfigFn{
// <T>(value:T):T;
// }
// var getData:ConfigFn=function<T>(value:T):T{
// return value;
// }
// getData<String>('zhangsan');
// getData<boolean>(false);
//泛型接口 第二种
interface ConfigFn<T>{
<T>(value:T):T;
}
function getData<T>(value:T):T{
return value;
}
var myGetData:ConfigFn<string>=getData;
myGetData('123');
/**
* 定义一个User的类这个类的作用就是映射数据库字段
* 然后定义一个MysqlDb的这个类用于操作数据库
* 然后把User类作为参数传入MysqlDb中
*/
// class ArticleCate{
// title:string|undefined;
// desc:string|undefined;
// status:number|undefined;
// }
// class User{
// username:string|undefined;
// password:string|undefined;
// }
// class MysqlDb{
// add(info:ArticleCate):boolean{//校验用户则使用user:User
// console.log(info);
// return true;
// }
// }
// // var u=new User();
// // u.username='zhangsan';
// // u.password='123456';
// // var Db=new MysqlDb();
// // Db.add(u);
// var art=new ArticleCate();
// art.status=1
// art.desc='国内新闻'
// art.title='国内'
// var Db=new MysqlDb();
// Db.add(art);
//操作数据库的泛型类
class MysqlDb<T>{
add(info:T):boolean{
console.log(info);
return true;
}
update(info:T,id:number):boolean{
console.log(info);
console.log(id);
return true;
}
}
//想给User表增加数据
//1.定义一个User类和数据库进行映射
class User{
username:string | undefined;
password:string | undefined;
}
var u=new User();
u.username='张三';
u.password='123456';
var Db=new MysqlDb<User>();
Db.add(u);
//2.定义文章分类的类
class ArticleCate{
title:string | undefined;
desc:string | undefined;
status:number | undefined;
constructor(params:{
title:string | undefined,
desc:string | undefined,
status?:number | undefined
}){
this.title=params.title;
this.desc=params.desc;
this.status=params.status;
}
}
var art=new ArticleCate({
title:'分类11',
desc:'123',
status:1
});//打印的时候出现undefined注意检查构造函数右边是不是params.
art.status=0;
//把类当作参数的泛型类
var myDb=new MysqlDb<ArticleCate>();
myDb.update(art,12);
通过ts泛型模拟不同数据库使用
/**
* 定义一个操作数据库的库 支持Mysql Mssql MongoDb
*
* 要求1:Mysql Mssql MongoDb功能一样 都有 add update delete get方法
* 注意:约束统一的规范,以及代码重构
*
* 解决方案:需要约束规范所以要定义接口,需要代码重用所以使用泛型
* 1.接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范
* 2.泛型 通俗理解:泛型就是解决 类 接口 方法的复用性
*
*/
interface DBI<T>{
add(info:T):boolean;
update(id:number):boolean;
get(id:number):any[];
}
//定义一个操作mysql数据库的类
class MySqlDb<T> implements DBI<T>{
add(info: T): boolean {
console.log('mysql数据库连接成功');
return true;
}
update(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
//定义一个操作mssql数据库的类
class MsSqlDb<T> implements DBI<T>{
add(info: T): boolean {
console.log('mssql数据库连接成功');
return true;
}
update(id: number): boolean {
throw new Error("Method not implemented.")
}
get(id: number): any[] {
var list=[
{
title:'xxx',
desc:'xxxxx'
},
{
title:'xx1',
desc:'xxxx1'
}
]
return list;
}
}
//操作用户表 定义一个User类和数据表映射
class User{
username:string | undefined
password:string | undefined
}
var u=new User();
u.password='123';
u.username='lisi';
var oMySql=new MySqlDb<User>();
oMySql.add(u);
var oMssql=new MsSqlDb<User>();
oMssql.add(u);
var data=oMssql.get(4);
console.log(data);
ts结构之命名空间,模块
概念:
- 命名空间:
- 在代码量比较打的情况下,为了避免各种变量命名相冲突,可将相似功能的函数,类,接口等防止到命名空间内同java的包,.net的命名空间一样,ts的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。
- 命名空间和模块的区别:
命名空间:内部模块,主要用于组织代码,避免命名冲突
模块:ts的外部模块的简称,侧重代码的复用,一个模块可能会有多个模块
初识命名空间概念以及namespace,export关键字
先认识一些关键词:namespace命名空间类似于java的包,namespace A{代码},namespace B{代码},这样即使代码一模一样也不影响,因为A和B是完全互相不干扰的空间,在此空间下所有的代码都是私有的,在空间外实例需要A.(A点),但是实例类需要实例的类前面有被关键字export(导出)修饰。
看看下列示例:
说明export关键字的类,是通过无法调用命名空间点类来实例,我们修改一下,让B的Dog也被修饰。
证明此结论,其作用就是用于区分,组织代码,避免命名冲突
命名空间模块化
首先在根目录下,创建modules模块目录,将A,B命名空间放在这个modules下的a.ts中,并且使用export命名空间导出命名空间A,B暴露出来,再在index.ts中导入我们要的模块的ts文件,详细请看下图
然后使用cmd打开js目录,使用node index.js进行渲染,才能看见效果,因为浏览器看不出模块export暴露效果。
出现了错误:ReferenceError: document is not defined,此前的代码有一些可能对渲染有影响,先将之前代码剪切到一个新的ts文件下,index.js下只剩当前需要测试的代码。
再重新测试:
证明成功
测试导多个命名空间:
index.ts下的代码
/*
命名空间:
在代码量比较打的情况下,为了避免各种变量命名相冲突,可将相似功能的函数,类,接口等防止到命名空间内
同java的包,.net的命名空间一样,ts的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。
命名空间和模块的区别:
命名空间:内部模块,主要用于组织代码,避免命名冲突
模块:ts的外部模块的简称,侧重代码的复用,一个模块可能会有多个模块
*/
import {A,B} from './modules/a';
var d=new A.Dog('小黑');
d.eat();
var dog=new A.Dog('小白');
dog.eat();
ts之装饰器
装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或者参数上,可以修改类的行为
通俗的讲修饰器就是一个方法,可以注入到类,方法,属性参数上
来扩展类,属性,方法,参数的功能
- 常见的装饰器:类装饰器,属性装饰器,方法装饰器,参数装饰器
- 装饰器的写法:普通装饰器(无法传参),装饰器工厂(可传参)
- 装饰器是过去几年中js最大的成就之一,已经是ES7的标准特性之一
开启ES7标准
先注释了模块导入的代码,再开始编写修饰器相关代码,当然要先配置打开es7检查。那怎么打开呢,一个是全局打开,一个是在项目的tsconfig处打开,不然会出现编译报错的情况,能运行但是看着很难受!
注释打开:"experimentalDecorators": true,
不打开的话:
打开就不报错
关于去波浪线的解决方案,更详细得请看我另外一篇文章:
接下来先介绍 类装饰器
1.类装饰器:类装饰器在类声明之前被声明(紧靠着声明),类装饰器应用于类构造函数,可以用来监视,修改或替换定义。
先看看普通类装饰器
//类装饰器 //普通装饰器
function logClass(params:any){
console.log(params);
//params就是当前类
params.prototype.apiUrl='动态扩展的属性';
params.prototype.run=function(){
console.log('我是一个run方法');
}
}
@logClass
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.run();
可以扩展原有代码的功能属性,如下图看结果可知
普通修饰器无法传参构造增强,其增强更多依赖于prototype原型
当然传参这一块也是有解决方案的,来看看修饰工厂:
//1.2 类装饰器:装饰工厂(可传参)
function logClass(params:string){
return function(target:any){//注意要写any,target表示当前要装饰的目标
console.log(target);
console.log(params);
}
}
@logClass('hello')
class HttpClient{
constructor(){
}
getData(){
}
}
function logClass(params:string){//这里的params为传参的值
return function(target:any){//注意要写any,target表示当前要装饰的目标
console.log(target);
console.log(params);
target.prototype.apiUrl=params;
}
}
@logClass('http://www.baidu.com')
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
普通装饰器能做的,它也能做
接下来介绍:重载构造函数的例子
/*
1.类装饰器
下面是一个重载构造函数的例子
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数
如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
*/
function logClass(target:any){
console.log(target);
return class extends target{
apiUrl:any='我是修改后的值';
getData(){
this.apiUrl=this.apiUrl+'----'
console.log(this.apiUrl);
}
}
}
@logClass
class HttpClient{
public apiUrl:string | undefined;
constructor(){
this.apiUrl='我是构造函数里面的apiUrl';
}
getData(){
console.log(this.apiUrl);
}
}
var http=new HttpClient();
http.getData();
属性装饰器
/**
* 2.属性装饰器
* 属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
* 1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
* 2.成员的名字
*/
//类装饰器
function logClass(params:any){
return function(target:any){
console.log(params);
console.log(target);
}
}
//属性装饰器
function logProperty(params:any){
return function(target:any,attr:any){
console.log(target);
console.log(attr);
target[attr]=params;//这是es6的写法
}
}
//@logClass('xxxx')
class HttpClient{
@logProperty('http://baidu.com')
public url:string | undefined;
constructor(){
}
getData(){
console.log(this.url);
}
}
var http=new HttpClient();
http.getData();
方法装饰器
方法装饰器
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义
方法修饰会再运行时传入下列3个参数:
1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2.成员的名字
3.成员的属性描述符
//方法装饰器1
function get(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc);
target.apiUrl='xxxx';
target.run=function(){
console.log('run');
}
}
}
class HttpClient{
public url:string | undefined;
constructor(){
}
@get('www.baidu.com')
getData(){
console.log(this.url);
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.getData();
//方法装饰器2
function get(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc.value);
//修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
//1.保存当前的方法
var oMethod=desc.value;
desc.value=function(...args:any[]){
args=args.map((value)=>{
return String(value);
})
console.log(args);
}
}
}
class HttpClient{
public url:string | undefined;
constructor(){
}
@get('www.baidu.com')
getData(){
console.log('我是getData里面的方法');
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.getData(123,'xxx');
稍微改造一下:
//方法装饰器2
function get(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc.value);
//修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
//1.保存当前的方法
var oMethod=desc.value;
desc.value=function(...args:any[]){
args=args.map((value)=>{
return String(value);
})
console.log(args);
oMethod.apply(this,args);
}
}
}
class HttpClient{
public url:string | undefined;
constructor(){
}
@get('www.baidu.com')
getData(...args:any[]){
console.log(args);
console.log('我是getData里面的方法');
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.getData(123,'xxx');
方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:
1. 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
2. 方法的名字
3. 参数在函数列表种的索引
/*
4.方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:
1.对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
2.方法的名字
3.参数在函数列表种的索引
*/
function logParams(params:any){
return function(target:any,methodName:any,paramsIndex:any){
console.log(params);
console.log(target);
console.log(methodName);
console.log(paramsIndex);
target.apiUrl=params;
}
}
class HttpClient{
public url:any| undefined
constructor(){
}
getData(@logParams('uid')uuid:any){
console.log('我是getData里面的方法');
}
}
var http:any=new HttpClient();
http.getData(1231);
console.log(http.apiUrl);
装饰器执行顺序
//装饰器执行顺序代码
/*
属性》方法》方法参数》类装饰器
如果有多个同样的装饰器,它会先执行后面的
*/
function logClass1(params:string){//这里的params为传参的值
return function(target:any){
console.log('类装饰器1');
}
}
function logClass2(params:string){//这里的params为传参的值
return function(target:any){
console.log('类装饰器1');
}
}
//属性装饰器
function logAttribute(params?:string){
return function(target:any,attrName:any){
console.log('属性装饰器');
}
}
//方法装饰器
function logMethod(params?:string){
return function(target:any,attrName:any,desc:any){
console.log('方法装饰器');
}
}
//方法参数装饰器
function logParams1(params?:string){
return function(target:any,attrName:any,desc:any){
console.log('方法参数装饰器1');
}
}
function logParams2(params?:string){
return function(target:any,attrName:any,desc:any){
console.log('方法参数装饰器2');
}
}
@logClass1('www.baidu.com')
@logClass2('www.360.com')
class HttpClient{
@logAttribute()
public apiUrl:string|undefined
constructor(){
}
@logMethod()
getData(){
return true;
}
setData(@logParams1() attr1:any,@logParams2() attr2:any){
}
}
var http:any=new HttpClient();
执行顺序结论:
属性》方法》方法参数》类装饰器 如果有多个同样的装饰器,它会先执行后面的