TS介绍
JS缺点:
1.旧JS 是弱类型语言,一个变量先后可以保存不同类型的数据(不可靠)
2.旧JS 是解释执行语言,一边解释,一边执行。一些低级错误无法提前检查和预警
3.旧JS 对对象要求不严格,开发人员想怎么写就怎么写,不便于大项目协作
TypeScript介绍:
是JavaScript 的一个超集(在原有的JS 语言基础上封装了一层更严格的规范)
支持ECMAScript 6 标准
TypeScript 由微软开发
设计目的是开发大型应用
注意: TS 不能被浏览器直接执行,但是TS 可以变异成纯 JS ,编译出来的JS 可以运行在任何浏览器或 nodejs 上。
TS 的新特性:类型检查、编译时错误检查、接口、访问修饰符、模块
TS的安装使用:
1. 全局安装TS 语言的编译器:npm i -g typescript
2. 用 vscode (vscode需要高版本)打开项目文件夹,右键选择在终端中打开,在终端中输入:tsc -init (说明tsc 是ts 语言的编译器,c 是compile 的意思,编译)
最后就是在当前项目文件夹中生成了tsconfig.json 文件,其中保存的是将ts 编译为js 时所需的配置,比如:
-- target:“ES5” 在将ts 文件编译为js 文件时,编译为ES5 的版本,兼容更多浏览器
-- module:“commenJS” 将来ts 文件中模块化开发所采用的标准
-- strict:true 将ts 文件编译js 文件时,自动启用严格模式
接下来就可以新建自己的ts 文件(first.ts):
//规定:a 变量将来只能保存数字类型的值 let a:number = 10 console.log(a)
再编译ts 文件为js 文件:打开命令行窗口,输入tsc first.ts
结果,tsc 编译器将.ts 文件的内容翻译为等效的js 文件,保存在ts 文件旁边的同名first.js文件中:
// first.js "use strict"; var a = 10; console.log(a); // 10
以上操作在实际项目中不可能每操作一步就去编译一次,所以,要配置自动编译:
在 vscode 中选择“终端”--“运行生成任务”--“tsc:监视”
配置后只要一自改ts文件,一旦保存就会自动编译,自动创建js 文件
不输入命令,运行js 文件:
1.先打开要运行的js 文件
2.点左边小虫 + 三角图标
3.点运行和调试
4.选择node.js
5.查看执行结果
ts中的变量和声明:
变量 ==》
1.旧的js 是弱类型语言,一个变量先后可以保存不同类型的数据(不可靠)
今后,只要在ts 中声明变量,都必须用“:数据类型”来规定
2.标准语法:var 或 const 或 let 变量名:数据类型 = 初始值
结果:将来这个变量只能保存规定的数据类型
比如 var a = 10 要换成 let a:number = 10; // 正确
a = “hello” 报错:不能将类型“string”分配给类型“number”
ts 能够写在冒号后的数据类型有哪些呢?
1.基本类型:boolean、number、string
2.数组:两种写法,结果一样
2-1.let 数组名:数据类型 [] = [值1,值2,...] 例如 let arr:string[] = ['a','b','c']
2-2.let 数组名:Array <数据类型> = [值1,值2,...]
3.any:可以匹配任何数据类型(对于不能确定的数组类型可以使用any定义)例如 var arr2 = ['a',1,true]
函数
1.既没有参数,又没有返回值的函数,与普通 js 写法一样
2.如果函数有返回值
3.如果函数有参数
4.既有形参,又有返回值
5.可选参数(一个形参可能有也可能没有)
?表示参数可以没有。将来如果没有传入这个参数值,则参数值默认为undefined
6.默认值
7.实参值个数不确定
// 无返回值的函数 const intr = () => { console.log(`I'm tom`) // I'm tom } intr(); // 带返回值的函数 const intr2 = ():string => { retrun `I'm tom` } console.log(intr2()) // I'm tom // 带参数的函数 const intr3 = (sname:string,sage:number):string => { retrun `I'm ${sname},I'm ${sage}` } console.log(intr3('tom',12)) // I'm tom,I'm 12 // 不确定参数 const intr4 = (sname:string,sage?:number):string => { if(sage === undefined){ retrun `I'm ${sname}` }else{ retrun `I'm ${sname},I'm ${sage}` } retrun `I'm ${sname},I'm ${sage}` } console.log(intr4('tom',10)) // I'm tom,I'm 10 console.log(intr4('tom')) // I'm tom // 默认值的参数 const intr5 = (sname:string,sage:any = '未知') => { console.log(`I'm ${sname},年龄:${sage}`) } intr5('tom',15) // I'm tom,年龄:15 intr5('tom') // I'm tom,年龄:未知 // 求和函数 const add = (...arr:number[]):number => { return arr.reduce((box,elem) => box+elem,0) } console.log(add(1,2,3)) // 6 console.log(add(1,2,3,4,5)) // 15
重载
旧 JS 中,重载只定义一个函数,在函数内根据传入的参数不同,执行不同的逻辑
function pay(){ if(arguments.length === 0){ 手机支付 } else if (arguments.length === 1){ 现金支付 } else { 刷卡支付 } } pay() pay(100) pay("6553 1234","123456")
TS中:
1.先要定义多个同名函数的声明,只要形参列表不同即可。但是不要实现函数体
function 函数名():void;
function 函数名(形参:数据类型):void;
注意:这里只是不同重载版本的声明,不包含函数定义
void 代表这个函数没有返回值
如果函数有返回值,则必须将void 改为返回值的具体类型
2.定义一个可实际执行多种任务的函数支持上方多种重载的情况
function pay():void; function pay(money:number):void; function pay(cardId:string,pwd:string):void; //括号里的a和b 也可以写成(...arr:any[])形式,判断arr.length打印对应的arr[index]值 function pay(a?:any,b?:any){ if(a === undefined){ console.log(`手机支付`) }else if(b === undefined){ console.log(`现金支付,收您${a}元`) }else{ console.log(`刷卡支付,从您卡号:${a} 扣款成功`) } } pay() // 手机支付 pay(100) // 现金支付,收您100元 pay('123456') //刷卡支付,从您卡号:123456 扣款成功
CLASS
定义class:
// 定义一个学生类型 class Student{ sname:string = ''; sage:number = 0; constructor(sname:string,sage:number){ this.sname = sname; this.sage = sage; } intr(){ console.log(`I'm ${this.sname},I'm ${this.sage}`) } } var tom = new Student("tom",11) as any; // ts中默认对象限制对象用中括号来访问的,所以如果一个对象需要去遍历,name需要添加as any 防止用中括号读取属性值时报错 console.log(tom); for(var key in tom){ console.log(`${key}:${tom[key]}`) } tom.intr()
两种类型间继承
子类型class:
// 类型继承 // 定义父类型 class Enemy{ x:number = 0; y:number = 0; constructor(x:number,y:number){ this.x = x; this.y = y; } fly(){ consle.log(`飞到x=${this.x},y=${this.y}位置`) } }
// 定义子类型 class Plane extends Enemy{ score:number = 0; constructor(x:number,y:number,score:number){ super(x,y); this.score = score } getScore(){ console.log(`击落敌机,得${this.score}分`) } } var p1 = new Plane(50,100,5) as any;
console.log(p1); for(var key in p1){ console.log(`${key}:${p1[key]}`) } p1.fly(); p1.getScore();
访问修饰符
class中的所有成员无论在class内,还是在子类型内,还是全局,都可用“this.属性名” 或 “父对象.属性名” 方式访问,没有限制。
但是有些数据,不想任所有人轻易都知道。旧的js 中就无法控制,所以ts 就产生了访问修饰符,是专门修饰一个属性或一个方法的可用范围的关键字(控制访问的范围),例如:访问控制修饰符 === 属性名:数据类型 = 初始值
访问修饰符有3种:
1. public 公有(默认),表示子类型和类外部都可以访问到的类型成
2. protected 受保护,表示只有父子类型范围内才能使用,外部不能用
3. private 私有,表示仅class 内可用,子类型和外部都不能用
// 公有 class Father{ moneyPublic:string = "爸爸可公开的钱"; fatherPay(){ console.log(`爸爸花${this.moneyPublic}买了包烟`) } } class Son extends Father{ sonPay(){ console.log(`孩子花${this.moneyPublic}买了玩具`) } } var f = new Father(); f.fatherPay(); // 爸爸花爸爸可公开的钱买了包烟 var s = new Son(); s.sonPay(); // 孩子花爸爸可公开的钱买了玩具 console.log(`妈妈花${f.moneyPublic}买了包`) // 妈妈花爸爸可公开的钱买了包 // 继承 class Father{ // 上面因为 public 是默认属性,所以可以不写 protected moneyPublic:string = "爸爸和儿子的小金库"; fatherPay(){ console.log(`爸爸花${this.moneyPublic}买了包烟`) } } class Son extends Father{ sonPay(){ console.log(`孩子花${this.moneyPublic}买了玩具`) } } var f = new Father(); f.fatherPay(); // 爸爸花爸爸和儿子的小金库买了包烟 var s = new Son(); s.sonPay(); // 孩子花爸爸和儿子的小金库买了玩具 console.log(`妈妈花${f.moneyPublic}买了包`) // 报错 // 私有 class Father{ private moneyPublic:string = "爸爸的私房钱"; fatherPay(){ console.log(`爸爸花${this.moneyPublic}买了包烟`) } } class Son extends Father{ sonPay(){ console.log(`孩子花${this.moneyPublic}买了玩具`) } } var f = new Father(); f.fatherPay(); // 爸爸花爸爸的私房钱买了包烟 var s = new Son(); s.sonPay(); // 报错 console.log(`妈妈花${f.moneyPublic}买了包`) // 报错
接口
用来规范按照要求实现程序结构,只要希望别人一定按照你的要求实现程序时,都用接口规范
// 定义学生class 的接口规范,并定义学生class 遵守接口规范 // 上级规定 interface IStudent{ sname:string; sage:number; intr():void; } // 开发人员 class Student2 implements IStudent{ sname:string = ""; sage:number = 0; constructor(sname:string,sage:number){ this.sname = sname; this.sage = sage; } intr():void{ console.log(`I'm${this.sname},I'm${this.sage}`) }; } var tom2 = new Student2('tom',11); console.log(tom2); // {sname:'tom',sage:11} tom.intr(); // I'm tom,I'm 11
模块化开发
旧JS 中,所有js 文件要几种引入到html 文件中才能运行,ts 中哪个文件想要使用另一个文件内容,直接引入即可,不用经过任何第三方
// 只抛出一个文件 interface IStudent{ sname:string; sage:number; intr():void; } export default IStudent; // 引入 import ISsudent from "./抛出文件名称" class Student implements IStudent{ sname:string = ''; sage:number = 0; intr():void{ console.log('打印.....') } } // 抛出多个 interface IStudent{ sname:string; sage:number; intr():void; } class Enemy{ x:number = 0; y:number = 0; constructor(x:number,y:number){ this.x = x; this.y = y; } fly(){ consle.log(`飞到x = ${this.x},y = ${this.y} 位置`) } } export {IStudent,Enemy}; // 引入(只引入文件中的其中一个) import { IStudent } from "./抛出的文件名称" class Student implements IStudent{ sname:string = ''; sage:number = 0; intr():void{ console.log('打印.....') } } // 其他文件中引入另一个 import { Enemy } from "./抛出的文件名称" class Plane extends Enemy{ score:number = 0; constructor(x:number,y:number,score:number){ super(x,y); this.score = score; } }