欢迎大家来到IT世界,在知识的湖畔探索吧!
TypeScript准备工作

欢迎大家来到IT世界,在知识的湖畔探索吧!
什么是TypeScript
TypeScript(下文简称为ts)是微软开发的一个开源的编程语言,通过在JavaScript(下文简称为js)的基础上添加静态类型定义构建而成。ts通过其编译器或Babel转译为js代码,可运行在任何浏览器,任何操作系统。ts是js的超集,它支持所有js的语法,我们可以在ts中使用原生js语法,可以简单的理解成TS是JS的升级版。
ts与js两者的主要的区别如下:
TypeScript JavaScript 强类型,需要强制转换类型 js是弱类型,没有静态类型选项,会自己根据环境变化自动转换类型 ts最终需要编程成js才能在浏览器中运行 js可以直接在浏览器中运行 ts是静态类型语言在编译期间就可以发现并纠正错误 js是动态类型语言在运行时才知道错误 支持模块、泛型和接口 不支持模块、泛型和接口
TypeScript学习环境
学习一门编程语言,首先有其编程环境,为了能方便快速的学习TypeScript语言,推荐一个在线的TypeScript的演练场,打开浏览器,输入网址即可使用,如下: https://www.typescriptlang.org/zh/play,界面如下:
TypeScript 安装
上面那种方式适合学习,但是工作时总不能这样来写代码,这里我们简单地说一下ts的环境搭建,首先我们需要先安装Node.js,我相信你已经会了,不会就百度嘛
然后我们打开命令行,执行如下命令:
npm install -g typescript
欢迎大家来到IT世界,在知识的湖畔探索吧!
安装完成后,使用如下命令查看是否安装成功,如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!tsc -v
然后我们打开vscode,创建一个ts文件(名为StudyTS.ts),写下第一条ts代码,如下:
console.log("我要关注郑大钱嗷,关注他,关注他");
然后我们在使用命令行,编译它,将ts,转化成js,命令如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!tsc StudyTS.ts
当你执行完这条命令的时候,就会理所当然的发现你会多了一个js文件,此时我们来执行这个js文件,命令如下:
node StudyTS.js
执行结果如下:
好了,到这里准备工作就完成了,下面正式开始发车
注释
常言道,兵马未动,粮草先行,我们首先说说注释,注释是不参与代码运行的,是给人看的,意义就是能够让代码更加的易读,更方便的理解代码,所以我们尽可能的养成写注释的好习惯。注释主要分为两种:单行注释和多行注释,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!// 这是单行注释 / * 这是多行注释 */
变量
变量的命名规范
- 变量名称只能有字母、数字、下划线组成,且不要为TypeScript 保留关键字
- 当变量名称由多个单词组成的时候,可以使用驼峰命名发,或者下划线风格,如:personName,person_name,都可以,最好不要写成personname,易读性差。
变量浅尝
// 声明一个变量 let perName:string = "郑大钱嗷" // 声明一个变量,不为其初始化 let sex:string; // 声明一个常量 const age:number =10 console.log(perName); console.log(age);
这里我们可以和编译后的js语法对比一下,如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!"use strict"; // 声明一个变量 let perName = "郑大钱嗷"; // 声明一个变量,不为其初始化 let sex; // 声明一个常量 const age = 10; console.log(perName); console.log(age);
可以发现我们在ts的代码中变量名称多了一个:和变量类型,这个就是限定变量的类型的,如果你想这个变量不需要类型显示,你可以使用js的语法,或者这样写
let perName:any = "郑大钱嗷"
此外假如你给一个变量限定类型为字符串,那么你赋一个整型的值就会报错,如图:
再者,如果我们声明了一个变量,但是没有初始化,如果没有使用该变量,则不会报错,但是如果使用的话就会报错。
变量的联合类型
我们上面限制的是一个类型,就是一个变量只能保存一个类型,我们也可以一个变量保存多个类型,这样这个变量就能保存多个类型的数据,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let varPro:string|boolean =true; console.log(varPro); varPro="郑大钱嗷"; console.log(varPro);
运行结果如下:
数组
数组就是一组数据,主要用来保存类型相同,含义相同的数据,比如我们要定义一个数组用来保存数字,示例代码如下:
let num:number[] = [1,2,3,4,5,6] console.log(`数字:${num}`);
运行结果如下:
上面我们是打印了所有的数组数据,假如我想取其中某个数据,这个时候需要指定索引,值得注意的是,索引是从0开始的,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let num:number[] = [1,2,3,4,5,6] console.log(`数字:${num[0]}`);
运行结果如下:
数组除了以上的声明方式之外,还可以使用Array类来声明,并且可以结合泛型来使用,具体在泛型类讲。
下面我们接着说数组的常用操作方法,直接看示例代码:
let array:number[] = [1,9,3,4,5,6]; console.log(`原始数组:${array}`); // 在数组的最后位置,添加元素 array.push(7); console.log(`数组的最后位置,添加元素${array}`); // 在数组的最前面,添加元素 array.unshift(0); console.log(`在数组的最前面,添加元素:${array}`); //删除最后面的元素 array.pop(); console.log(`删除最后面的元素:${array}`); //删除最前面的元素 array.shift(); console.log(`删除最前面的元素:${array}`); //从第几位开始删除几个元素,注意索引从0开始,splice的用法不仅是删除,更新数组的内容更贴切,有其他很多用法,可以自行百度 array.splice(0,1); console.log(`删除指定元素:${array}`); // 合并两个数组 let array2:number[] =[10,11,12]; array = array.concat(array2); console.log(`合并两个数组:${array}`); // 查找元素的位置 console.log(`查找元素的位置:${array.indexOf(10)}`); // 对数组进行正序排序 console.log(`对数组进行正序排序${array.sort()}`); // 对数组进行倒序序排序 console.log(`对数组进行正序排序${array.reverse()}`);
运行结果如下:
元组类型
欢迎大家来到IT世界,在知识的湖畔探索吧!// 声明一个元组 let person:[string,string,number] =['郑大钱嗷','男',18]; // 输出 console.log(person); console.log(person[0]);运行结果如下:
元组和数组的区别在于元组知道每个元素的类型,简单的说元组就是在数组的基础上对各个元素加了类型的限制。
字典类型
字典类型由键值对组成,键和值,示例代码如下:
// 声明一个字典,并赋值 let person:{[key:string ]:string }={ "name":"郑大钱嗷", "sex":"男" } // 获取name的值 console.log(person["name"]); // 修改name的值 person["name"]="郑大钱嗷~"; console.log(person["name"]);
运行结果如下:
枚举类型
当一个变量有多种值,然后值又是比较固定的,比如颜色,通常使用的主要颜色就那么几种,这个时候就可以将其定义成一个枚举类型,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!enum Color{ red, orange, yellow, green } console.log(Color.orange);
它最后会返回指定枚举的索引,示例代码如下:
模板字符串
模板字符串相当于定义一个模板,然后在模板里刨坑,然后再把值放在里面,这样就可以按照我们的要求显示字符串了,比直接使用+号拼接更加的方便。示例代码如下:
let perName:string = "郑大钱嗷" console.log(`名字:${perName}`);
typeof 类型验证
这个typeof的功能就是返回当前变量的数据类型,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let age = 18; console.log(typeof age);
运行结果如下:
类型别名
这个用的不多,基本不用,就是你觉得系统的number类型这个名字不好听,觉得原来的名字太委屈
这个时候你就可以给他换个名字,示例代码如下:
type haoTingNum = number;
let age:haoTingNum=18;
console.log(age);
运行结果如下:
运算符
算数运算符
算数运算符就是加减乘除、取余,自增和自减示例代码如下:
let a:number = 5; let b:number =6; console.log(`a+b=${a+b}`); console.log(`a-b=${a-b}`); console.log(`a*b=${a*b}`); console.log(`a/b=${a/b}`); console.log(`a%b=${a%b}`);
运行结果如下:
自增和自减运算符:所谓自增/减,就是在之前值的基础上自己加1或减1,自增/减,又分为前自增/减,和后自增/减,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let a:number = 5; // 先使用,后自增,此时使用的时候a还是5,使用后a的值为6 console.log(`a++:${a++}`); // 同样是先使用,后自减,此时使用的是a是6,使用后a的值是5 console.log(`a--:${a--}`); // 这里不一样了,是先自增,在使用,此时使用时a为6 console.log(`++a:${++a}`); // 这里是先自减,在使用,此时使用时a为6-1=5 console.log(`--a:${--a}`);
运行结果如下:
比较运算符
所谓比较运算符就是指大于、小于、等于(==、===)、不等于、大于等于、小于等于,比较运算符返回结果一个布尔值即ture或者false,示例代码如下:
let a:number=1; let b:number=2; let c:number=1; console.log(`a>b: ${a>b}`); console.log(`a<b: ${a<b}`); console.log(`a>=b: ${a>=b}`); console.log(`a<=b: ${a<=b}`); console.log(`a==b: ${a==b}`); console.log(`a===b: ${a===b}`); console.log(`a!=b: ${a!=b}`);
运行结果如下:
这里补充一下==和===的区别,如果是==比较的是值相等,而===不仅要求值相等,还要求数据类型相等。
逻辑运算符
逻辑运算符,主要有三种,与、或、非,三种,我们举个例子,比如我们想吃冷饮,但是我们有要求,我们必须要吃哈根达斯而且至少还得三个球,必须满足这两个条件,否则不吃。
示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let iceName:string="哈根达斯"; let qiuNum:number=5; if(iceName=="哈根达斯"&&qiuNum>=3){ console.log('好好吃') }else{ console.log('少球了,哼,不吃'); }
赋值运算符
赋值运算符是一种简写,具体有如下几种:=、+=、-+、*=、/=、%=,这里我们以加法举例,示例代码如下:
let a:number = 1; a+=1; let b:number = 1; b=b+1 console.log(`a:${a}`); console.log(`b:${b}`);
运行结果如下:
也就是说a+=1就等同于a=a+1。
条件语句 判断语句
所谓判断,即使如果这样,我会怎么样,如果那样,又会怎么样,比如上面得那个例子,让我偷下懒,直接拿过来用
欢迎大家来到IT世界,在知识的湖畔探索吧!let iceName:string="哈根达斯"; let qiuNum:number=5; if(iceName=="哈根达斯"&&qiuNum>=3){ console.log('好好吃') }else{ console.log('少球了,哼,不吃'); } 判断语法主要有如下几种结构,if…、if…else…、if…elseif…else…,我们来看一个经典的案例,根据分数来判断成绩的等级,示例代码如下:
let score:number =60; if(score>=90 && score<=100){ console.log("优秀"); }else if(score>=80 && score<90){ console.log("良好"); }else if(score>=70 && score<80){ console.log("中等"); }else if(score>=60 && score<70){ console.log("及格"); }else{ console.log("支棱起来,好嘛"); }
运行结果如下:
此外有个和判断语句类似的运算符,叫三目运算符,写起来更加的简单,具体示例如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!//三目运算符 条件?值1:值2 let sex:string ="男"; console.log(sex=="男"?"好帅啊":"好美啊")
运行结果如下:
当我们有多种条件判断的时候,if判断语句不是特别的好用,我们可以使用switch语句,示例代码如下:
enum Color{ red, black, green } let color:Color = Color.red switch(color){ case Color.red : console.log("red"); break; case Color.black : console.log("black"); break; case Color.green: console.log("green"); break; default: console.log("其他颜色"); }
运行结果如下:
这里要值得注意的是,每个条件分支要加break语句,否则匹配之后,还会继续匹配,这里的default就相当与if中的else,即所有分支都没有匹配到才会执行。
循环语句
所谓循环就是反复的执行某些事情,比如说,让唐僧念100遍经
我们肯定不可能这样写:
欢迎大家来到IT世界,在知识的湖畔探索吧!console.log("念经"); console.log("念经"); console.log("念经"); console.log("念经"); console.log("念经"); console.log("念经"); console.log("念经"); //...100遍
这样也可以实现,但是有点不太聪明的样子,于是我们需要更高级的魔法来实现,示例代码如下:
let i:number=1; // 先判断已经念了多少次了,有没有超过100次,没有超过就接着念,超过就不念了 while(i<=100){ console.log(`唐僧念经,第${i}次`); i++; } ]
上面是while…do..的写法,即先判断,在执行,还有一种do…while…的写法,即先执行再判断,代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let i:number=1; do{ console.log(`唐僧念经,第${i}次`); i++; }while(i<=100); ]
值得注意的一点是,循环的条件一定要有出口,即满足什么条件后,就不执行了,否则就会一直执行,就是死循环.
循环也可以遍历数据,示例代码如下:
let names:string[]=["郑","争","争"]; let i:number=0; while(i<names.length){ console.log(names[i]); i++; }
运行结果如下:
除了有while循环外,还有for循环,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let names:string[]=["郑","争","争"]; for(let j=0;j<names.length;j++){ console.log(names[j]); }
对于数组,我们for循环还有另一种写法,更方便,更加简单,示例代码如下:
let names:string[]=["郑","争","争"]; //是用of,是把值给name,如果是in,则是把索引给name for(let name of names){ console.log(name); }
函数
函数就是一段代码块,目的是为了能够更好的实现代码的复用,但我们定义了一个函数后,当我们需要使用的时候,就可以直接调用,代码的复用性大大提高,代码量会大大的减少
让我们先简单的感受一下:
欢迎大家来到IT世界,在知识的湖畔探索吧!// 定义一个有参数的函数 function saySomething(word:string):void{ console.log(word); } // 调用函数 saySomething("你好"); saySomething("我很好,非常好,老好了");
运行结果如下:
我们上面定义了一个函数,function 为定义函数的关键字,函数名为saySomething,里面的word,为传入函数的参数,我们一般成为入参,同样有入参肯定就有出参,这里的void表示没有返回值,即没有出参,我们这个函数没有定义出参,下面我们定义一个加法的方法来返回一个出参,示例代码如下:
function add(num1:number,num2:number){ return num1+num2;// 返回计算结果 } console.log(add(1,3));
运行结果如下:
上面的函数,还可以有如下2种写法,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let add = function(num1:number,num2:number){ return num1+num2; } console.log(add(1,3)); let add2 =(num1:number,num2:number) =>{ return num1+num2; } console.log(add(1,3)); console.log(add2(1,3));
面向对象
什么是对象?在我们在说对象之前,我们了解一下类,我们把一切具有共性的事务可以定义成一个类,类就相当于一个模板,比如狗、猫、猪,都可以当成一个类,那什么是对象呢,对象就是对类的具体实现,比如猪是一个类,但是猪有好多种,有苏格兰打卤猪、黑猪、野猪、母猪等等,我们可以一句话总结一下:类是对象的抽象,而对象是类的具体化
我们先来感受一下,示例代码如下:
// 定义一个猪类 class Pig{ //定义类的熟悉 name:string="猪"; age:number = 1; constructor(name:string,age:number){ this.name=name; this.age=age; } eat():void{ console.log("吃东西") } } //实例化对象 let pig1 = new Pig("飞猪",10); pig1.eat();
我们受限创建了一个Pig的类型,里面定义了两个属性name和age,下面的constructor为构造方法,所谓构造方法就是当你对对象实例化的时候,就执行的方法,如果构造方法需要传参的时候,那么再实例化对象的时候就需要为其传入参数,否则会报错,下面的eat方法就是普通的方法。
我们实例化的时候,需要使用 new关键字来实例化,实例化完成后,我们就可以使用对象了。
静态(成员)属性和静态(成员)方法
静态属性、方法就是有static关键字修饰的,不需要实例化对象,使用类名就可以调用,而成员属性、方法是属于对象的,需要实例化后才能调用,实例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!// 定义一个猪类 class Pig{ //定义类的熟悉 name:string="猪"; age:number = 1; static belong:string="动物" constructor(name:string,age:number){ this.name=name; this.age=age; } eat():void{ console.log("吃东西") } static sleep():void{ console.log("睡觉觉") } } //实例化对象 let pig1 = new Pig("飞猪",10); //成员方法调用 pig1.eat(); console.log(pig1.name); //静态方法调用 Pig.sleep(); console.log(Pig.belong);
运行结果如下:
继承
所谓继承就是子类继承父类,就与儿子继承父亲的财产是一样,比如我们有一个父类为车类,然后我们有一个子类为面包车,为了方便代码的复用以及可拓展性,我们可以先定义父类,然后用子类继承父类,这样子类就不需要重新编写了,只需要再父类的基础上就行修改就可以了,示例代码如下:
// 定义一个Car类 class Car{ color:string = "black"; seats:number= 5; startCar():void{ console.log("启动汽车") } } // 子类继承父类 class MianBaoCar extends Car{ } let car1 = new MianBaoCar(); car1.startCar();
我们定义了一个父类Car,然后子类MianBaoCar继承父类,这样子类就可以调用父类的方法了,但是如果父类的方法不适合子类的方法,我们想要覆盖父类的方法,应该怎么做呢,我们只需要在子类种定义一个方法与父类中的方法同名,就可以覆盖父类的方法,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!// 定义一个Car类 class Car{ color:string = "black"; seats:number= 5; startCar():void{ console.log("启动汽车"); } } class MianBaoCar extends Car{ startCar():void{ console.log("启动面包车"); } } let car1 = new MianBaoCar(); car1.startCar();
运行结果如下:
但是此时你想,我不要完全覆盖,我想要在父类之前的方法上拓展,怎么做呢,我们可以使用super关键字,来调用父类的方法后再拓展,示例代码如下:
// 定义一个Car类 class Car{ color:string = "black"; seats:number= 5; startCar():void{ console.log("启动汽车"); } } class MianBaoCar extends Car{ startCar():void{ super.startCar(); console.log("呜呜呜~~~~"); } } let car1 = new MianBaoCar(); car1.startCar();
运行结果如下:
抽象类
所谓抽象类,就是抽取子类共有的部分,仅仅做定义,不做具体的实现,具体的实现需要在子类中实现,且子类必须实现,我们看一个简单的示例:
欢迎大家来到IT世界,在知识的湖畔探索吧!// 定义一个抽象类 abstract class Person{ abstract name:string; abstract say():void; } class Student extends Person{ name="郑大钱嗷" say(){ console.log("说话") } } let stu:Person = new Student(); stu.say();
运行结果如下:
接口
由于ts只能进行单继承,没有办法实现多继承,接口就是为了弥补ts没有多继承的特性,同时接口也是相当于一个规范,当子类使用一个接口的时候,需要实现接口里的所有方法,示例代码如下:
class Person{ name:string ='人' } interface Wolf{ bite():void;//只能定义,不能实现 } class WolfMan extends Person implements Wolf{ bite(){ console.log("撕咬~") } } let a = new WolfMan(); a.bite();
运行结果如下:
私有属性及其操作(属性寄存器)
如果有接触过java的同学,就会发现这个很熟悉,就是setter和getter方法,即对属性取值和赋值的时候,只能通过setter/getter方法,这样可以很好的保护属性的值,下面我们看一个示例:
欢迎大家来到IT世界,在知识的湖畔探索吧!class Person{ _hp:number = 100; //使用的名字的话 前面必须要加上_ // 取值 set hp(value){ // 如果hp小于0,直接赋值为0,这样就不会出现负数了 if (value<0){ this._hp=0; }else{ this._hp=value; } } // 赋值 get hp():number{ return this._hp; } } let a = new Person(); a.hp=-10; console.log(a.hp)
运行结果如下:
命名空间
命名空间的出现主要是为了区分代码中定义的标识符,通过 namespace 关键字声明命名空间,在命名空间外部需要通过完全限定名访问这些对象,这样即便有同名的类名、变量,也不会有冲突,示例代码如下:
// 声明命名空间 namespace space1{ // 需要导出,否则会有报错 export class Person{ } } namespace space2{ export class Person{ } } // 实例化的时候,需要使用命名空间.类名的形式 let a = new space1.Person();
泛型
所谓泛型根据字面意思了解,就是宽泛的类型,通常用于类和函数,用于对不特定数据类型的支持,也就是输入的参数类型是可变的,根据你的输入参数类型来决定,我们先看一段示例代码
欢迎大家来到IT世界,在知识的湖畔探索吧!function addT<T>(num:T):T{ if (typeof num=="number"){ num++; return num; } return num; } console.log(addT(3));
运行结果
上面的的<T>表示的就是一个泛型,出参和入参都是可变的,且两者的类型一致,比如你输入的是一个number数据类型,那么上面的函数一定返回number类型。
在数组的声明中,我们也可以使用泛型,示例代码如下:
// 使用泛型声明一个空的数组 let array: Array<number> = new Array<number>(); console.log(array);
运行结果如下:
回调
我们之前在定义函数的时候,我们的入参一般是一个值,但是现在我们传入的不是一个值,而是一个函数体。
欢迎大家来到IT世界,在知识的湖畔探索吧!function func(value:Function){ value(); } function add(){ console.log("测试方法"); } func(add)
运行结果如下:
除了上面的写法外,我们还有另一种写法,匿名函数,示例代码如下:
function func(value:Function){ value(); } func(function add(){ console.log("测试方法"); })
我们也可以使用箭头函数的方式,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!function func(value:Function){ value(); } func(()=>{ console.log("测试方法"); });
上面的函数是没有传入参数的,我们也可以传入参数,示例代码如下:
function func(value:Function){ value("测试"); } func((str:string)=>{ console.log(str); });
正则表达式
正则表达式就是用来匹配一系列符合某些语法规则的字符串,正则表达式通常被用来检索、替换符合某个模式的文本。正则表达式是由普通字符、元字符、限定符组成,具体的这里就不展开说了,主要看一下,ts中正则表达式的使用,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!let reg =/\d{2}-\d{4}/g; let str:string="1111-"; // 输出匹配结果 let res = reg.exec(str); console.log(`匹配的次数:${res.length}`); // 输出匹配的内容 res.forEach(function(value,index){ console.log(`value:${value},index:${index}`); });
运行的结果如下:
访问修饰符
public 修饰符
示例代码如下:
class Person{ // public 公开的,属性默认为public,表示属性和方法,内部和外部都可以访问 public name: string|undefined; public say(){ } } class Student extends Person{ constructor(){ super(); } } let a:Person = new Person(); a.name=""; a.say();
public表示 公开的,属性默认为public,表示属性和方法,内部、外部、子类都可以访问
protected 修饰符
示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!class Person{ protected name: string|undefined; protected say(){ } } class Student extends Person{ constructor(){ super(); } }
protected修饰符表示受保护的,在内部和子类都可以访问,但是外部无法访问。
private 私有的
示例代码
class Person{ private name: string|undefined; private say(){ } } class Student extends Person{ constructor(){ super(); } }
protected修饰符表示私有的,只能在内部访问,但是子类、外部无法访问。
单例模式
单例模式,就是通过单例模式的方法创建的类在当前进程中只有一个实例,示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!class Manager{ // 内部创建自己的对象,并用静态修饰 static Instance = new Manager(); // 构造方法,私有化,不能让外部new对象 private constructor(){ } } console.log(Manager.Instance);
我们还有第二种写法,示例代码如下:
class Manager{ // 内部创建自己的对象,并用静态修饰 private static instance:Manager; // 构造方法,私有化,不能让外部new对象 private constructor(){ } static Instance(){ // 如果没有单例产生就创建单例 if(!Manager.instance){ Manager.instance = new Manager(); } return Manager.instance; } } Manager.Instance();
代理模式
为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。简单的说我要做一件事,但是我不做,我去找一个人(即:代理人)给我做,然后给我返回结果。
欢迎大家来到IT世界,在知识的湖畔探索吧!// 定义一个接口 interface Calc{ calc(a:number,b:number):number; } // 代理人1,实现接口,要想做代理人,必须要实现计算的方法 class Agent1 implements Calc{ calc(a:number,b:number){ return a+b; } } // 代理人2 class Agent2 implements Calc{ calc(a:number,b:number){ return a+b; } } class Person{ currAgent: Calc; getNum(a:number,b:number){ console.log(this.currAgent.calc(a,b)); } } let person = new Person(); person.currAgent = new Agent1(); person.getNum(1,3);
运行结果如下:
观察者模式
当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。示例代码如下:
interface Listener{ changeName(name:string):void; } class Person { private _perName:string=""; // 所有观察者 obListeners:Array<Listener> = new Array<Listener>(); set perName(value:string){ this._perName=value; for(let listener of this.obListeners){ listener.changeName(this._perName); } } get perName():string{ return this._perName } } class Test implements Listener{ changeName(newName:string){ console.log("名字有变化!,新名称:"+newName); } } let per = new Person(); let listener1 = new Test(); let listener2 = new Test(); per.obListeners.push(listener1); per.obListeners.push(listener2); per.perName="郑大钱嗷"
运行结果如下:
工厂模式
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行,在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。示例代码如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!enum CarType{ BenZ, Audi, Bmw } class Car{ name:string=""; // 工厂方法 static createCar(carType:CarType):Car{ let car:Car; switch(carType){ case CarType.Audi: car = new Audi(); break; case CarType.BenZ: car = new Benz(); break; case CarType.Bmw: car = new Bmw(); break; } return car; } } class Benz extends Car{} class Audi extends Car{} class Bmw extends Car{} Car.createCar(CarType.Audi);
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/112363.html