当前位置: 首页 > news >正文

备案号被取消 没有重新备案网站会被关闭吗网站开发招标公告

备案号被取消 没有重新备案网站会被关闭吗,网站开发招标公告,wordpress模板小说,建设通网站账号TypyScript从入门到精通 TypyScript 是什么#xff1f;增加了什么环境搭建二、为何需要 TypeScript三、编译 TypeScript四、类型声明五、类型推断基本类型六、类型总览JavaScript 中的数据类型TypeScript 中的数据类型1. 上述所有 JavaScript 类型2. 六个新类型#xff1a;3.… TypyScript从入门到精通 TypyScript 是什么增加了什么环境搭建二、为何需要 TypeScript三、编译 TypeScript四、类型声明五、类型推断基本类型六、类型总览JavaScript 中的数据类型TypeScript 中的数据类型1. 上述所有 JavaScript 类型2. 六个新类型3. 两个用于自定义类型的方式 1. 原始类型 VS 包装对象 七、常用类型与语法1. any2. unknown3. never4. void5. object6. tuple7. enum8. type9. 一个特殊情况10. 复习类相关知识11. 属性修饰符12. 抽象类13. interface接口14. 一些相似概念的区别14.1. interface 与 type 的区别14.2. interface 与 抽象类的区别 八、泛型九、类型声明文件类抽象类 接口等用法 TypyScript 是什么 TypeScript由微软开发是基于JavaScript的一个扩展语言。 TypeScript包含了JavaScript的所有内容即TypeScript是JavaScript的超集。 TypeScript增加了静态类型检查、接口、 泛型等很多现代开发特性更适合大型项目的开发。 TypeScript需要编译为JavaScript然后交给浏览器或其他JavaScript运行环境执行。 增加了什么 环境搭建 二、为何需要 TypeScript 1️⃣今非昔比的 JavaScript了解 · JavaScript 当年诞生时的定位是浏览器脚本语言用于在网页中嵌入简单的逻辑且代码量很少。 · 随着时间的推移JavaScript 变得越来越流行如今的 JavaScript 已经可以全栈编程了。 · 现如今的 JavaScript 应用场景比当年丰富的多代码量也比当年大很多随便一个 JavaScript 项目的代码量可以轻松的达到几万行甚至十几万行 · 然而 JavaScript 当年“出生简陋”没考虑到如今的应用场景和代码量逐渐就出现了很多困扰。 2️⃣JavaScript 中的困扰 不清楚的数据类型 let welcome hellowelcome() // 此行报错TypeError: welcome is not a function有漏洞的逻辑 const str Date.now() % 2 ? 奇数 : 偶数if (str ! 奇数) {alert(hello)} else if (str 偶数) {alert(world)}访问不存在的属性 const obj { width: 10, height: 15 };const area obj.width * obj.heigth;低级的拼写错误 const message hello,worldmessage.toUperCase() 3️⃣『静态类型检查』 · 在代码运行前进行检查发现代码的错误或不合理之处减小运行时出现异常的几率此种检查叫『静态类型检查』TypeScript 和核心就是『静态类型检查』简言之就是把运行时的错误前置。 同样的功能TypeScript 的代码量要大于 JavaScript但由于 TypeScript 的代码结构更加清晰在后期代码的维护中 TypeScript 却胜于 JavaScript。 三、编译 TypeScript 浏览器不能直接运行 TypeScript 代码需要编译为 JavaScript 再交由浏览器解析器执行。 命令行编译 要把.ts文件编译为.js文件需要配置TypeScript的编译环境步骤如下 · 第一步创建一个demo.ts文件例如 const person {name:李四,age:18}console.log(我叫${person.name}我今年${person.age}岁了)· 第二步全局安装TypeScript npm i typescript -g· 第三步使用命令编译.ts文件 tsc demo.ts 自动化编译 · 第一步创建TypeScript编译控制文件 tsc --init工程中会生成一个tsconfig.json配置文件其中包含着很多编译时的配置。 观察发现默认编译的JS版本是ES7我们可以手动调整为其他版本。 · 第二步监视目录中的.ts文件变化 tsc --watch 或 tsc -w· 第三步小优化当编译出错时不生成.js文件 tsc --noEmitOnError --watch备注当然也可以修改tsconfig.json中的noEmitOnError配置 四、类型声明 使用:来对变量或函数形参进行类型声明 let a: string //变量a只能存储字符串let b: number //变量b只能存储数值let c: boolean //变量c只能存储布尔值a helloa 100 //警告不能将类型“number”分配给类型“string”b 666b 你好//警告不能将类型“string”分配给类型“number”c truec 666 //警告不能将类型“number”分配给类型“boolean”// 参数x必须是数字参数y也必须是数字函数返回值也必须是数字function demo(x:number,y:number):number{return x y}demo(100,200) demo(100,200) //警告类型“string”的参数不能赋给类型“number”的参数demo(100,200,300) //警告应有 2 个参数但获得 3 个demo(100) //警告应有 2 个参数但获得 1 个在:后也可以写字面量类型不过实际开发中用的不多。 let a: 你好 //a的值只能为字符串“你好”let b: 100 //b的值只能为数字100a 欢迎//警告不能将类型“欢迎”分配给类型“你好”b 200 //警告不能将类型“200”分配给类型“100”五、类型推断 TS会根据我们的代码进行类型推导例如下面代码中的变量d只能存储数字 let d -99 //TypeScript会推断出变量d的类型是数字d false //警告不能将类型“boolean”分配给类型“number”但要注意类型推断不是万能的面对复杂类型时推断容易出问题所以尽量还是明确的编写类型声明 基本类型 六、类型总览 JavaScript 中的数据类型 ①string ②number ③boolean ④null ⑤undefined ⑥bigint ⑦symbol ⑧object 备注其中object包含Array、Function、Date、Error等… TypeScript 中的数据类型 1. 上述所有 JavaScript 类型 2. 六个新类型 ①any ②unknown ③never ④void ⑤ tuple ⑥ enum 3. 两个用于自定义类型的方式 ①type ②interface 注意点 在JavaScript中的这些内置构造函数Number、String、Boolean用于创建对应的包装对象 在日常开发时很少使用在TypeScript中也是同理所以在TypeScript中进行类型声明时通常都是用小写的number、string、boolean 例如下面代码 let str1: stringstr1 hellostr1 new String(hello) //报错let str2: Stringstr2 hellostr2 new String(hello)console.log(typeof str1)console.log(typeof str2)1. 原始类型 VS 包装对象 · 原始类型如number、string、boolean在 JavaScript 中是简单数据类型它们在内存中占用空间少处理速度快。 · 包装对象如Number对象、String对象、Boolean对象是复杂类型在内存中占用更多空间在日常开发时很少由开发人员自己创建包装对象。 自动装箱JavaScript 在必要时会自动将原始类型包装成对象以便调用方法或访问属性 // 原始类型字符串let str hello;// 当访问str.length时JavaScript引擎做了以下工作 let size (function() {// 1. 自动装箱创建一个临时的String对象包装原始字符串let tempStringObject new String(str);// 2. 访问String对象的length属性let lengthValue tempStringObject.length;// 3. 销毁临时对象返回长度值// JavaScript引擎自动处理对象销毁开发者无感知return lengthValue;})(); console.log(size); // 输出: 5七、常用类型与语法 1. any any的含义是任意类型一旦将变量类型限制为any那就意味着放弃了对该变量的类型检查。 // 明确的表示a的类型是 any —— 【显式的any】 let a: any // 以下对a的赋值均无警告a 100a 你好a false// 没有明确的表示b的类型是any但TS主动推断出来b是any —— 隐式的anylet b //以下对b的赋值均无警告b 100b 你好b false注意点any类型的变量可以赋值给任意类型的变量/* 注意点any类型的变量可以赋值给任意类型的变量 */let c:anyc 9let x: stringx c // 无警告2. unknown unknown的含义是未知类型适用于起初不确定数据的具体类型要后期才能确定 unknown可以理解为一个类型安全的any。 // 设置a的类型为unknownlet a: unknown //以下对a的赋值均符合规范a 100a falsea 你好// 设置x的数据类型为stringlet x: stringx a //警告不能将类型“unknown”分配给类型“string” unknown会强制开发者在使用之前进行类型检查从而提供更强的类型安全性。 // 设置a的类型为unknownlet a: unknowna hello//第一种方式加类型判断if(typeof a string){x a console.log(x)}//第二种方式加断言x a as string//第三种方式加断言x stringa读取any类型数据的任何属性都不会报错而unknown正好与之相反。 let str1: stringstr1 hellostr1.toUpperCase() //无警告let str2: anystr2 hellostr2.toUpperCase() //无警告let str3: unknownstr3 hello;str3.toUpperCase() //警告“str3”的类型为“未知”// 使用断言强制指定str3的类型为string(str3 as string).toUpperCase() //无警告3. never never的含义是任何值都不是即不能有值例如undefined、null、‘’、0都不行 几乎不用never去直接限制变量因为没有意义例如 /* 指定a的类型为never那就意味着a以后不能存任何的数据了 */let a: never// 以下对a的所有赋值都会有警告a 1 a truea undefineda nullnever一般是TypeScript主动推断出来的例如 // 指定a的类型为stringlet a: string// 给a设置一个值a helloif (typeof a string) {console.log(a.toUpperCase())} else {console.log(a) // TypeScript会推断出此处的a是never因为没有任何一个值符合此处的逻辑}never也可用于限制函数的返回值 // 限制throwError函数不需要有任何返回值任何值都不行像undeifned、null都不行 function throwError(str: string): never {throw new Error(程序异常退出: str)} 4. void void的含义是空即函数不返回任何值调用者也不应依赖其返回值进行任何操作 void通常用于函数返回值声明 function logMessage(msg:string):void{console.log(msg)}logMessage(你好)注意编码者没有编写return指定函数返回值所以logMessage函数是没有显式返回值的但会有一个隐式返回值 是undefined虽然函数返回类型为void但也是可以接受undefined的简单记undefined是void可以接受的一种“空”。 以下写法均符合规范 // 无警告function logMessage(msg:string):void{console.log(msg)}// 无警告function logMessage(msg:string):void{console.log(msg)return;}// 无警告function logMessage(msg:string):void{console.log(msg)return undefined}那限制函数返回值时是不是undefined和void就没区别呢—— 有区别。因为还有这句话 【返回值类型为void的函数调用者不应依赖其返回值进行任何操作】对比下面两段代码 function logMessage(msg:string):void{console.log(msg)}let result logMessage(你好)if(result){ // 此行报错无法测试 void 类型的表达式的真实性console.log(logMessage有返回值)}function logMessage(msg:string):undefined{console.log(msg)}let result logMessage(你好)if(result){ // 此行无警告console.log(logMessage有返回值)}理解 void 与 undefined · void是一个广泛的概念用来表达“空”而 undefined 则是这种“空”的具体实现。 · 因此可以说 undefined是void能接受的一种“空”的状态。 · 也可以理解为void包含undefined但void所表达的语义超越了undefinedvoid是一种意图上的约定而不仅仅是特定值的限制。 总结 如果一个函数返回类型为void那么 从语法上讲函数是可以返回undefined的至于显式返回还是隐式返回这无所谓 从语义上讲函数调用者不应关心函数返回的值也不应依赖返回值进行任何操作即使我们知道它返回了undefined。 5. object 关于object与Object直接说结论实际开发中用的相对较少因为范围太大了。 object小写 object小写的含义是所有非原始类型可存储对象、函数、数组等由于限制的范围比较宽泛在实际开发中使用的相对较少。 let a:object //a的值可以是任何【非原始类型】包括对象、函数、数组等 // 以下代码是将【非原始类型】赋给a所以均符合要求a {}a {name:张三}a [1,3,5,7,9]a function(){}a new String(123)class Person {}a new Person()// 以下代码是将【原始类型】赋给a有警告a 1 // 警告不能将类型“number”分配给类型“object”a true // 警告不能将类型“boolean”分配给类型“object”a 你好 // 警告不能将类型“string”分配给类型“object” a null // 警告不能将类型“null”分配给类型“object”a undefined // 警告不能将类型“undefined”分配给类型“object”Object大写 · 官方描述所有可以调用Object方法的类型。 · 简单记忆除了undefined和null的任何值。 · 由于限制的范围实在太大了所以实际开发中使用频率极低。 let b:Object //b的值必须是Object的实例对象除去undefined和null的任何值 // 以下代码均无警告因为给a赋的值都是Object的实例对象b {}b {name:张三}b [1,3,5,7,9]b function(){}b new String(123)class Person {}b new Person()b 1 // 1不是Object的实例对象但其包装对象是Object的实例b true // truue不是Object的实例对象但其包装对象是Object的实例b 你好 // “你好”不是Object的实例对象但其包装对象是Object的实例// 以下代码均有警告b null // 警告不能将类型“null”分配给类型“Object”b undefined // 警告不能将类型“undefined”分配给类型“Object”声明对象类型 实际开发中限制一般对象通常使用以下形式 // 限制person1对象必须有name属性age为可选属性let person1: { name: string, age?: number }// 含义同上也能用分号做分隔let person2: { name: string; age?: number }// 含义同上也能用换行做分隔let person3: {name: stringage?: number}// 如下赋值均可以person1 {name:李四,age:18}person2 {name:张三}person3 {name:王五}// 如下赋值不合法因为person3的类型限制中没有对gender属性的说明person3 {name:王五,gender:男} 索引签名 允许定义对象可以具有任意数量的属性这些属性的键和类型是可变的常用于描述类型不确定的属性具有动态属性的对象。 // 限制person对象必须有name属性可选age属性但值必须是数字同时可以有任意数量、任意类型的其他属性let person: {name: stringage?: number[key: string]: any // 索引签名完全可以不用key这个单词换成其他的也可以}// 赋值合法person {name:张三,age:18,gender:男 }声明函数类型 let count: (a: number, b: number) numbercount function (x, y) {return x y }备注 · TypeScript 中的在函数类型声明时表示函数类型描述其参数类型和返回类型。 · JavaScript 中的是一种定义函数的语法是具体的函数实现。 · 函数类型声明还可以使用接口、自定义类型等方式下文中会详细讲解。 声明数组类型 let arr1: string[] let arr2: Arraystringarr1 [a,b,c]arr2 [hello,world]备注上述代码中的Array属于泛型下文会详细讲解。 6. tuple 元组(Tuple)是一种特殊的数组类型可以存储固定数量的元素并且每个元素的类型是已知的且可以不同。元组用于精确描述一组值的类型?表示可选元素。 // 第一个元素必须是 string 类型第二个元素必须是 number 类型。let arr1: [string,number]// 第一个元素必须是 number 类型第二个元素是可选的如果存在必须是 boolean 类型。let arr2: [number,boolean?]// 第一个元素必须是 number 类型后面的元素可以是任意数量的 string 类型let arr3: [number,...string[]]// 可以赋值arr1 [hello,123]arr2 [100,false]arr2 [200]arr3 [100,hello,world]arr3 [100]// 不可以赋值arr1声明时是两个元素赋值的是三个arr1 [hello,123,false]7. enum 枚举enum可以定义一组命名常量它能增强代码的可读性也让代码更好维护。 如下代码的功能是根据调用walk时传入的不同参数执行不同的逻辑存在的问题是调用walk时传参时没有任何提示编码者很容易写错字符串内容并且用于判断逻辑的up、down、left、right是连续且相关的一组值那此时就特别适合使用 枚举enum。 function walk(str:string) {if (str up) {console.log(向【上】走);} else if (str down) {console.log(向【下】走);} else if (str left) {console.log(向【左】走);} else if (str right) {console.log(向【右】走);} else {console.log(未知方向);}}walk(up)walk(down)walk(left)walk(right)数字枚举 数字枚举一种最常见的枚举类型其成员的值会自动递增且数字枚举还具备反向映射的特点在下面代码的打印中不难发现可以通过值来获取对应的枚举成员名称 。 // 定义一个描述【上下左右】方向的枚举Directionenum Direction {Up,Down,Left,Right}console.log(Direction) // 打印Direction会看到如下内容/* {0:Up, 1:Down, 2:Left, 3:Right, Up:0, Down:1, Left:2,Right:3} */// 反向映射console.log(Direction.Up)console.log(Direction[0])// 此行代码报错枚举中的属性是只读的Direction.Up shang也可以指定枚举成员的初始值其后的成员值会自动递增。 enum Direction {Up 6,Down,Left,Right}console.log(Direction.Up); // 输出: 6console.log(Direction.Down); // 输出: 7使用数字枚举完成刚才walk函数中的逻辑此时我们发现 代码更加直观易读而且类型安全同时也更易于维护。 enum Direction {Up,Down,Left,Right,}function walk(n: Direction) {if (n Direction.Up) {console.log(向【上】走);} else if (n Direction.Down) {console.log(向【下】走);} else if (n Direction.Left) {console.log(向【左】走);} else if (n Direction.Right) {console.log(向【右】走);} else {console.log(未知方向);}}walk(Direction.Up)walk(Direction.Down)字符串枚举 枚举成员的值是字符串 enum Direction {Up up,Down down,Left left,Right right}let dir: Direction Direction.Up;console.log(dir); // 输出: up常量枚举 官方描述常量枚举是一种特殊枚举类型它使用const关键字定义在编译时会被内联避免生成一些额外的代码。 何为编译时内联 所谓“内联”其实就是 TypeScript 在编译时会将枚举成员引用替换为它们的实际值而不是生成额外的枚举对象。这可以减少生成的 JavaScript 代码量并提高运行时性能。 使用普通枚举的 TypeScript 代码如下 enum Directions {Up,Down,Left,Right}let x Directions.Up;编译后生成的 JavaScript 代码量较大 “use strict”; var Directions; (function (Directions) { Directions[Directions[Up] 0] Up;Directions[Directions[Down] 1] Down;Directions[Directions[Left] 2] Left;Directions[Directions[Right] 3] Right;})(Directions || (Directions {})); let x Directions.Up; 使用常量枚举的 TypeScript 代码如下 const enum Directions { Up, Down, Left, Right } let x Directions.Up; 编译后生成的 JavaScript 代码量较小 “use strict”; let x 0 /* Directions.Up */; 8. type type可以为任意类型创建别名让代码更简洁、可读性更强同时能更方便地进行类型复用和扩展。 基本用法 类型别名使用type关键字定义type后跟类型名称例如下面代码中num是类型别名。 type num number;let price: numprice 100联合类型 联合类型是一种高级类型它表示一个值可以是几种不同类型之一。 type Status number | stringtype Gender 男 | 女function printStatus(status: Status) {console.log(status);}function logGender(str:Gender){console.log(str)}printStatus(404);printStatus(200);printStatus(501);logGender(男)logGender(女)3.交叉类型 交叉类型Intersection Types允许将多个类型合并为一个类型。合并后的类型将拥有所有被合并类型的成员。交叉类型通常用于对象类型。 / /面积type Area {height: number; //高width: number; //宽};//地址type Address {num: number; //楼号cell: number; //单元号room: string; //房间号};// 定义类型House且House是Area和Address组成的交叉类型type House Area Address;const house: House {height: 180,width: 75,num: 6,cell: 3,room: 702};9. 一个特殊情况 先来观察如下两段代码 代码段1正常 在函数定义时限制函数返回值为void那么函数的返回值就必须是空。 function demo():void{// 返回undefined合法return undefined// 以下返回均不合法return 100return falsereturn nullreturn []}demo()代码段2特殊 使用类型声明限制函数返回值为void时TypeScript并不会严格要求函数返回空。 type LogFunc () voidconst f1: LogFunc () {return 100; // 允许返回非空值};const f2: LogFunc () 200; // 允许返回非空值const f3: LogFunc function () {return 300; // 允许返回非空值};为什么会这样 是为了确保如下代码成立我们知道 Array.prototype.push 的返回值是一个数字而Array.prototype.forEach方法期望其回调的返回类型是void。 const src [1, 2, 3];const dst [0];src.forEach((el) dst.push(el));官方文档的说明Assignability of Functions 10. 复习类相关知识 本小节是复习类相关知识如果有相关基础可以跳过。 class Person {// 属性声明name: stringage: number// 构造器constructor(name: string, age: number) {this.name namethis.age age}// 方法speak() {console.log(我叫${this.name}今年${this.age}岁)}}// Person实例const p1 new Person(周杰伦, 38)class Student extends Person {grade: string// 构造器constructor(name: string, age: number, grade: string) {super(name, age)this.grade grade}// 备注本例中若Student类不需要额外的属性Student的构造器可以省略// 重写从父类继承的方法override speak() {console.log(我是学生我叫${this.name}今年${this.age}岁在读${this.grade}年级,)}// 子类自己的方法study() {console.log(${this.name}正在努力学习中......)}}11. 属性修饰符 public 修饰符 class Person {// name写了public修饰符age没写修饰符最终都是public修饰符public name: stringage: numberconstructor(name: string, age: number) {this.name namethis.age age}speak() {// 类的【内部】可以访问public修饰的name和ageconsole.log(我叫${this.name}今年${this.age}岁)}}const p1 new Person(张三, 18)// 类的【外部】可以访问public修饰的属性 console.log(p1.name)class Student extends Person {constructor(name: string, age: number) {super(name, age)}study() {// 【子类中】可以访问父类中public修饰的name属性、age属性console.log(${this.age}岁的${this.name}正在努力学习)}}属性的简写形式 class Person {public name: string;public age: number;constructor(name: string, age: number) {this.name name;this.age age;}}class Person {constructor(public name: string,public age: number) { }}protected 修饰符 class Person {// name和age是受保护属性不能在类外部访问但可以在【类】与【子类】中访问constructor(protected name: string,protected age: number) {}// getDetails是受保护方法不能在类外部访问但可以在【类】与【子类】中访问protected getDetails(): string {// 类中能访问受保护的name和age属性return 我叫${this.name}年龄是${this.age}}// introduce是公开方法类、子类、类外部都能使用introduce() {// 类中能访问受保护的getDetails方法console.log(this.getDetails());}}const p1 new Person(杨超越,18)// 可以在类外部访问introducep1.introduce()// 以下代码均报错// p1.getDetails()// p1.name// p1.ageclass Student extends Person {constructor(name:string,age:number){super(name,age)}study(){// 子类中可以访问introducethis.introduce()// 子类中可以访问nameconsole.log(${this.name}正在努力学习)}}const s1 new Student(tom,17)s1.introduce()private 修饰符 class Person {constructor(public name: string,public age: number,// IDCard属性为私有的(private)属性只能在【类内部】使用private IDCard: string) { }private getPrivateInfo(){// 类内部可以访问私有的(private)属性 —— IDCardreturn 身份证号码为${this.IDCard}}getInfo() {// 类内部可以访问受保护的(protected)属性 —— name和agereturn 我叫: ${this.name}, 今年刚满${this.age}岁;}getFullInfo(){// 类内部可以访问公开的getInfo方法也可以访问私有的getPrivateInfo方法return this.getInfo() this.getPrivateInfo()}}const p1 new Person(张三,18,110114198702034432)console.log(p1.getFullInfo())console.log(p1.getInfo())// 以下代码均报错// p1.name// p1.age// p1.IDCard// p1.getPrivateInfo()readonly 修饰符 class Car {constructor(public readonly vin: string, //车辆识别码为只读属性public readonly year: number,//出厂年份为只读属性public color: string,public sound: string) { }// 打印车辆信息displayInfo() {console.log(识别码${this.vin},出厂年份${this.year},颜色${this.color},音响${this.sound});}}const car new Car(1HGCM82633A123456, 2018, 黑色, Bose音响);car.displayInfo()// 以下代码均错误不能修改 readonly 属性// car.vin 897WYE87HA8SGDD8SDGHF; // car.year 2020; 12. 抽象类 · 概述抽象类是一种无法被实例化的类专门用来定义类的结构和行为类中可以写抽象方法也可以写具体实现。抽象类主要用来为其派生类提供一个基础结构要求其派生类必须实现其中的抽象方法。 · 简记抽象类不能实例化其意义是可以被继承抽象类里可以有普通方法、也可以有抽象方法。 通过以下场景理解抽象类 我们定义一个抽象类Package表示所有包裹的基本结构任何包裹都有重量属性weight包裹都需要计算运费。但不同类型的包裹如标准速度、特快专递都有不同的运费计算方式因此用于计算运费的calculate方法是一个抽象方法必须由具体的子类来实现。 abstract class Package {constructor(public weight: number) { }// 抽象方法用来计算运费不同类型包裹有不同的计算方式abstract calculate(): number// 通用方法打印包裹详情printPackage() {console.log(包裹重量为: ${this.weight}kg运费为: ${this.calculate()}元);}}StandardPackage类继承了Package实现了calculate方法// 标准包裹class StandardPackage extends Package {constructor(weight: number,public unitPrice: number // 每公斤的固定费率) { super(weight) }// 实现抽象方法计算运费calculate(): number {return this.weight * this.unitPrice;}}// 创建标准包裹实例const s1 new StandardPackage(10,5)s1.printPackage()ExpressPackage类继承了Package实现了calculate方法class ExpressPackage extends Package {constructor(weight: number,private unitPrice: number, // 每公斤的固定费率快速包裹更高private additional: number // 超出10kg以后的附加费) { super(weight) }// 实现抽象方法计算运费calculate(): number {if(this.weight 10){// 超出10kg的部分每公斤多收additional对应的价格return 10 * this.unitPrice (this.weight - 10) * this.additional}else {return this.weight * this.unitPrice;}}}// 创建特快包裹实例const e1 new ExpressPackage(13,8,2)e1.printPackage()总结何时使用抽象类 定义通用接口为一组相关的类定义通用的行为方法或属性时。 提供基础实现在抽象类中提供某些方法或为其提供基础实现这样派生类就可以继承这些实现。 确保关键实现 强制派生类实现一些关键行为。 共享代码和逻辑当多个类需要共享部分代码时抽象类可以避免代码重复。 13. interface接口 interface是一种定义结构的方式主要作用是为类、对象、函数等规定一种契约这样可以确保代码的一致性和类型安全但要注意interface只能定义格式不能包含任何实现 定义类结构 // PersonInterface接口用与限制Person类的格式interface PersonInterface {name: stringage: numberspeak(n: number): void}// 定义一个类 Person实现 PersonInterface 接口class Person implements PersonInterface {constructor(public name: string,public age: number) { }// 实现接口中的 speak 方法speak(n: number): void {for (let i 0; i n; i) {// 打印出包含名字和年龄的问候语句console.log(你好我叫${this.name}我的年龄是${this.age});}}}// 创建一个 Person 类的实例 p1传入名字 tom 和年龄 18const p1 new Person(tom, 18);p1.speak(3)定义对象结构 interface UserInterface {name: stringreadonly gender: string // 只读属性age?: number // 可选属性run: (n: number) void}const user: UserInterface {name: 张三,gender: 男,age: 18,run(n) {console.log(奔跑了${n}米)}};定义函数结构 interface CountInterface {(a: number, b: number): number;}const count: CountInterface (x, y) {return x y}接口之间的继承 一个interface继承另一个interface从而实现代码的复用interface PersonInterface {name: string // 姓名age: number // 年龄}interface StudentInterface extends PersonInterface {grade: string // 年级}const stu: StudentInterface {name: 张三,age: 25,grade: 高三,}接口自动合并可重复定义 // PersonInterface接口interface PersonInterface {// 属性声明name: stringage: number}// 给PersonInterface接口添加新属性interface PersonInterface {// 方法声明speak(): void}// Person类实现PersonInterfaceclass Person implements PersonInterface {name: stringage: number// 构造器constructor(name: string, age: number) {this.name namethis.age age}// 方法speak() {console.log(你好我是老师:, this.name)}}总结何时使用接口 定义对象的格式 描述数据模型、API 响应格式、配置对象…等等是开发中用的最多的场景。 类的契约规定一个类需要实现哪些属性和方法。 扩展已有接口一般用于扩展第三方库的类型 这种特性在大型项目中可能会用到。 14. 一些相似概念的区别 14.1. interface 与 type 的区别 · 相同点interface和type 都可以用于定义对象结构在定义对象结构时两者可以互换。 · 不同点 1️⃣interface更专注于定义对象和类的结构支持继承、合并。 2️⃣type可以定义类型别名、联合类型、交叉类型但不支持继承和自动合并。 // 使用 interface 定义 Person 对象interface PersonInterface {name: string;age: number;speak(): void;}// 使用 type 定义 Person 对象type PersonType {name: string;age: number;speak(): void;};// 使用PersonInterface/* let person: PersonInterface {name:张三,age:18,speak(){console.log(我叫${this.name}年龄${this.age})}} */// 使用PersonTypelet person: PersonType {name:张三,age:18,speak(){console.log(我叫${this.name}年龄${this.age})}}interface PersonInterface {name: string // 姓名age: number // 年龄}interface PersonInterface {speak: () void}interface StudentInterface extends PersonInterface {grade: string // 年级}const student: StudentInterface {name: 李四,age: 18,grade: 高二,speak() {console.log(this.name,this.age,this.grade)}}// 使用 type 定义 Person 类型并通过交叉类型实现属性的合并type PersonType {name: string; // 姓名age: number; // 年龄} {speak: () void;};// 使用 type 定义 Student 类型并通过交叉类型继承 PersonTypetype StudentType PersonType {grade: string; // 年级};const student: StudentType {name: 李四,age: 18,grade: 高二,speak() {console.log(this.name, this.age, this.grade);}};14.2. interface 与 抽象类的区别 · 相同点都能定义一个类的格式定义类应遵循的契约 · 不相同 1️⃣接口只能描述结构不能有任何实现代码一个类可以实现多个接口。 2️⃣抽象类既可以包含抽象方法也可以包含具体方法 一个类只能继承一个抽象类。 // FlyInterface 接口interface FlyInterface {fly(): void;}// 定义 SwimInterface 接口interface SwimInterface {swim(): void;}// Duck 类实现了 FlyInterface 和 SwimInterface 两个接口class Duck implements FlyInterface, SwimInterface {fly(): void {console.log(鸭子可以飞);}swim(): void {console.log(鸭子可以游泳);}}// 创建一个 Duck 实例const duck new Duck();duck.fly(); // 输出: 鸭子可以飞duck.swim(); // 输出: 鸭子可以游泳八、泛型 泛型允许我们在定义函数、类或接口时使用类型参数来表示未指定的类型这些参数在具体使用时才被指定具体的类型泛型能让同一段代码适用于多种类型同时仍然保持类型的安全性。 举例如下代码中就是泛型不一定非叫T设置泛型后即可在函数中使用T来表示该类型 function logDataT(data: T): T {console.log(data)return data}logDatanumber(100)logDatastring(hello)function logDataT, U(data1: T, data2: U): T | U {console.log(data1,data2)return Date.now() % 2 ? data1 : data2}logDatanumber, string(100, hello)logDatastring, boolean(ok, false)interface PersonInterfaceT {name: string,age: number,extraInfo: T}let p1: PersonInterfacestringlet p2: PersonInterfacenumberp1 { name: 张三, age: 18, extraInfo: 一个好人 }p2 { name: 李四, age: 18, extraInfo: 250 }interface LengthInterface {length: number}// 约束规则是传入的类型T必须具有 length 属性function logPersonT extends LengthInterface(data: T): void {console.log(data.length)}logPersonstring(hello)// 报错因为number不具备length属性// logPersonnumber(100)class PersonT {constructor(public name: string,public age: number,public extraInfo: T) { }speak() {console.log(我叫${this.name}今年${this.age}岁了)console.log(this.extraInfo)}}// 测试代码1const p1 new Personnumber(tom, 30, 250);// 测试代码2type JobInfo {title: string;company: string;}const p2 new PersonJobInfo(tom, 30, { title: 研发总监, company: 发发发科技公司 });九、类型声明文件 类型声明文件是 TypeScript 中的一种特殊文件通常以.d.ts 作为扩展名。它的主要作用是为现有的 JavaScript 代码提供类型信息使得 TypeScript 能够在使用这些 JavaScript 库或模块时进行类型检查和提示。 export function add(a, b) {return a b;}export function mul(a, b) {return a * b;}declare function add(a: number, b: number): number;declare function mul(a: number, b: number): number;export { add, mul };// example.tsimport { add, mul } from ./demo.js;const x add(2, 3); // x 类型为 numberconst y mul(4, 5); // y 类型为 numberconsole.log(x,y)var myage:number 100 var myshow:boolean true myshow false var myvalue:string|number100 myvaluekerwinconsole.info(myshow) console.info(myage) console.info(myvalue)export default{} /*** 第一种风格*/ var myarr:string[] [a,b] myarr.push(c);var myarr1:number[] [1,2,3] myarr1.push(5)var myarr2:(string|number)[] [12, a] myarr2.push(45)var myarr3:any[] [12,33,,true]console.info(myarr) console.info(myarr1) console.info(myarr2) console.info(myarr3) // 第二种风格var mylist:Arraystring [a,b] var mylist1:Arraynumber [1,2,3] var mylist2:Arraystring|number [1,2,3,a] var mylist3:Arrayany [1,2,3]console.info(mylist) console.info(mylist1) console.info(mylist2) console.info(mylist3)/*** 元祖固定长度的数组*/let h:[string,string]; h [abc,dec] // 对象 这种写法没有约束 var obj {name:myname,age:12 }obj.age23; obj.namezhangsan console.info(obj)//用接口约定对象interface MyObject{name:string,age:number,location?:string, // 可选属性[propName:string]:any //任意属性 }var myobjec:MyObject;myobjec {name:zhangsan,age:12,location:dalian,a:1,b:2,c:4} console.info(myobjec)/*** 另外一种方式定义对象结构* ? 表示该属性可选*/let myobj:{name:string, age?:number} myobj {name:孙猴子, age: 12} myobj {name:孙猴子}/*** [prop:string]:any 表示后面可以添加任意类型的属性多个*/ let b :{name:string, [prop:string]:any}b {name:猪八戒,age:12, gener:男} function test(a:number, b:number) :number{return ab; }var myresut test(1,2);console.info(myresut);/*** 设置函数结果的声明*/let d:(a:number,b:number) number;d function(n1, n2) {return n1n2;} enum Gener {male 1,female0 }let i : {name:string,gener:Gener}; i {name:孙猴子,gener:Gener.female }console.info(i)类抽象类 接口等用法 // 使用class关键字来定义一个类/* 对象中主要包含两个部分属性方法*/class Person{/* 直接定义的属性是实例属性需要通过对象的实例去访问const per new Person();per.name使用static的开头的属性是静态属性类型可以直接通过类去访问Person.agereadonly 开头的属性表示一个只读的属性无法修改*///定义实例属性// name: string 孙悟空;// readonly name: string 孙悟空;name 孙悟空;// 在属性前使用static关键字可以定义类属性静态属性// static readonly age: number 18;age 18;//定义方法/* 如果方法以static开头则方法就是类方法可以直接通过类去调用*/sayHello(){console.log(Hello 大家好)} }//new 一个实例 const per new Person();console.log(per.name);per.name tom; console.log(per.name) // console.log(Person.age); //static时可以使用// Person.sayHello();per.sayHello();class Dog {name: string;age: number;// constructor 被称为构造函数// 构造函数会在对象创建时调用constructor(name: string, age: number) {// 在实例方法中this就表示当前的实例// 在构造函数中当前对象就是当前新建的那个对象// 可以通过this向新建的对象中添加属性// console.log(this);this.name name,this.age age}bark(){alert(汪汪汪);console.log(this.name);} }const dog new Dog(小黑, 4); const dog2 new Dog(小白, 2); // const dog3 new Dog(); // const dog4 new Dog();console.log(dog); console.log(dog2); // console.log(dog3); // console.log(dog4);dog.bark(); (function (){// 定义一个Animal类class Animal{name: string;age: number;constructor(name: string, age: number){this.name name;this.age age;}sayHello(){console.log(动物在叫!!);}}/* Dog extends Animal- 此时Animal被称为父类Dog被称为子类- 使用继承后子类将会拥有父类所有的方法和属性- 通过继承可以将多个类中共有的代码写在一个父类这样只需要写一次即可让所有的子类都同时拥有父类中的属性和方法- 如果子类中添加了和父类相同的方法则子类方法会覆盖掉父类的方法这种子类覆盖掉父类方法的形式我们称为重写*///定义一个表示狗的类//使Dog类继承Animal类class Dog extends Animal{// name: string;// age: number;// constructor(name: string, age: number){// this.name name;// this.age age;// }// sayHello(){// console.log(汪汪汪!!);// }run(){console.log(${this.name}在跑啊~~);}sayHello(){console.log(汪汪汪!!);}}// 定义一个猫的类//使Cat类继承Animal类class Cat extends Animal{// name: string;// age: number;// constructor(name: string, age: number){// this.name name;// this.age age;// }// sayHello(){// console.log(喵喵喵!!);// }sayHello(){console.log(喵喵喵!!);}}const dog new Dog(旺财, 5);const cat new Cat(咪咪, 3);console.log(dog);dog.sayHello();dog.run();console.log(cat);cat.sayHello();})();/* OCP原则OPEN CLOSE开闭原则对扩展开放对修改关闭 */(function () {class Animal{name: string;constructor(name: string){this.name name;}sayHello(){console.log(动物在叫~~)}}class Dog extends Animal{age: numberconstructor(name: string, age: number){//如果在子类中写了构造函数在子类构造函数中必须对父类的构造函数进行调用super(name);//调用父类的构造函数this.age age;}sayHello() {// 在类的方法中 super就表示当前类的父类// super.sayHello();console.log(汪汪汪~~)}}const dog new Dog(旺财, 3);dog.sayHello(); })()(function () {/* 以abstract 开头的类是抽象类抽象类和其他类区别不大只是不能用来创建对象抽象类就是专门用来被继承的类抽象类中可以添加抽象方法*/abstract class Animal{name: string;constructor(name: string){this.name name;}// 定义一个抽象方法// 抽象方法使用abstract开头没有方法体// 抽象方法只能定义在抽象类中子类必须对抽象方法进行重写abstract sayHello():void;// sayHello(){// console.log(动物在叫~~)// }}class Dog extends Animal{sayHello() {console.log(汪汪汪~~)}}class Cat extends Animal{sayHello() {console.log(喵喵喵~~)}}const dog new Dog(旺财);dog.sayHello();const an new Animal();//无法创建抽象类的实例dog.sayHello(); })()(function () {// 描述一个对象的类型type myType {name: string,age: number};/* 接口用来定义一个类结构, 用来定义一个类中应该包含哪些属性和方法同时接口也可以当成类型声明去使用*/interface myInterface{name: string;age: number;}interface myInterface{gender: string;}const obj: myInterface {name: sss,age: 111,gender: 男};/*接口可以在定义类的时候去限制类的结构接口中所有的属性都不能有实际的值接口只定义对象的结构而不考虑实际值在接口中所有的方法都是抽象类*/interface myInter{name: string;sayHello(): void;}/* 定义类时可以使类去实现一个接口实现接口就是使类满足接口的要求*/class MyClass implements myInter{name: string;constructor(name: string){this.name name;}sayHello(){console.log(大家好~~~);}}})();(function(){// 定义一个表示人的类class Person{//TS可以在属性前添加属性的修饰符/* public 修饰的属性可以在任意位置访问修改 默认值private 私有属性, 私有属性只能在类内部进行访问修改- 通过再类中添加方法使得私有属性可以被外部访问protected 受保护的属性,只能在当前类和当前类的子类中访问(修改)*/public _name: string;private _age: number;constructor(name: string, age: number) {this._name name;this._age age;}/* getter 方法来读取属性setter 方法来设置属性- 他们被称为属性的存取器*//* // 定义方法 用来获取name属性getName(){return this._name;}// 定义方法用来设置name属性setName(value: string){this._name value;}//getAge(){return this._age;}setAge(value: number){// 判断年龄是否合法if(value 0){this._age value;}} */// TS中设置getter方法的方式get name(){console.log(get name()执行了!!);return this._name;}set name(value:string){this._name value;}set age(value:number){if(value 0){this._age value}}}const per new Person(孙悟空, 18);/* 现在属性是在对象中设置的属性可以任意的被修改属性可任意被修改将会导致对象中的数据变得非常不安全*/// per._name 猪八戒;// per._age -38;// per.setName(猪八戒);// per.setAge(-33);// console.log(per);per.name 猪八戒;per.age -13console.log(per);class A{protected num: number;constructor(num: number){this.num num;}}class B extends A{test(){console.log(this.num);}}const b new B(125);// b.num 33// class C{// name: string;// age: number;// // 可以直接将属性定义在构造函数中// constructor(name: string, age:number){// this.name name;// this,age age;// }// }class C{// 语法糖// 可以直接将属性定义在构造函数中constructor(public name: string, public age:number){}}const c new C(李明康,18);console.log(c);})();/* function fn(a: number):number {return a; } *//* 在定义函数或是类时,如果遇到类型不明确就可以使用泛型 */function fnT(a:T):T {return a; }// 可以直接调用具有泛型的函数 let result fn(10);// 不指定泛型,TS可以自动对类型进行推断let result2 fnstring(hello);//手动指定泛型// 泛型可以同时指定多个 function fn2T, K(a:T, b:K):T {console.log(b);return a;}fn2number, string(123, hello);interface Inter{length: number; }// T extends Inter 表示泛型T必须是Inter实现类(子类) function fn3T extends Inter(a:T): number {return a.length }class MyClassT{name: T;constructor(name:T){this.name name;} }const mc new MyClassstring(孙悟空);fn3(124); // fn3(1243); fn3({length: 10});
http://www.tj-hxxt.cn/news/223550.html

相关文章:

  • app购物网站建设网站设计制作的服务商
  • 昆明网站seo多少钱免费域名解析网站建设
  • 网站布局模板舟山高端网站建设
  • 网站优化策划方案网站管理员登陆域名
  • 洛阳作公司网站做h5的网站页面
  • 学做网站要什么基础wordpress配置报错
  • 专业长春网站建设哪家好火车头采集器和wordpress
  • 做外贸的人经常用什么网站重庆旅游网站建设地址
  • 漳州专业网站建设费用wordpress 压缩gif插件
  • 石家庄市建设局质监站网站中国网络营销论坛
  • 马蜂窝是什么做的网站wordpress视频防盗链
  • 班级网站素材下载网站建设收获与体会
  • 有哪些在线做图的网站电子商务网站设计html模板
  • 南充做网站略奥网络网站优化排名公司
  • 做外文翻译的网站制作图片软件免费版
  • 国内旅行做行程网站wordpress模板是什么意思
  • 广州seo网站推广技巧app手机软件
  • 可不可以自己做网站沙井做网站的公司
  • 建设搜索引擎友好的网站对做网站有什么建议
  • 电信网站备案系统做网站都需要什么资料
  • 江苏省建设斤网站有没有专门的销售公司
  • 岚县网站建设全网关键词优化公司哪家好
  • 网站建设管理经验做法盗网站asp源码
  • 电器网站建设免费咨询上海网站架设
  • 做外销网站总部在深圳的互联网公司
  • 怎么做网站添加二维码男科医院咨询免费
  • 网站的评测系统怎么做的做招聘的h5用哪个网站
  • 网站流量盈利知己图书网站建设策划书
  • 视频网页制作教程360优化大师官网
  • 如何给网站的关键词做排名架设一个网站