前提:
1. 視頻鏈接:
2. 文件鏈接:
3. 官網(wǎng):
一、簡(jiǎn)介
google研發(fā),為了面向大型復(fù)雜的項(xiàng)目,使用javascript可以搭建
ts 是 javascript 的超集,包含 es6 和 es5
實(shí)現(xiàn)類似 java | c# 這種面向?qū)ο蟮木幊陶Z言
ts 是由 c# 之父 Anders Hejlsberg 發(fā)起的
建議使用 es6 語法
二、使用
1. 安裝
npm|cnpm install -g typescript
或者
yarn global add typescript
安裝成功如下圖:
2. 使用
創(chuàng)建文件 hello.ts
寫入ts語法ts 編譯成 es5 語法
瀏覽器本身不支持ts語法
命令:tsc hello.ts
注意:每次運(yùn)行都需要編譯-
配置自動(dòng)化編譯腳本
- 創(chuàng)建 tsconfig.json 文件
tsc --init
生成配置文件 - 快捷鍵 Ctrl+shift+B 選擇監(jiān)視模式 進(jìn)行編譯
每次有更新就會(huì)編譯
tsc watch 是自動(dòng)監(jiān)聽,下次保存文件就自動(dòng)編譯
tsc build 是編譯一次 - 創(chuàng)建 tsconfig.json 文件
三.語法
以下 typescript 簡(jiǎn)寫為 ts
1.數(shù)據(jù)類型
ts 中 為了 使代碼更規(guī)范,更有利于維護(hù),增加了類型校驗(yàn)
變量一旦確定為哪個(gè)數(shù)據(jù)類型,不可改變數(shù)據(jù)類型
函數(shù)返回值類型等等語法比較嚴(yán)格,不然語法會(huì)報(bào)錯(cuò)
序號(hào) | 類型 | 標(biāo)識(shí)符 | 含義 | 備注 | 是否基本類型 |
---|---|---|---|---|---|
1 | 布爾類型 | boolean | [true/false] | let flag:boolean=false |
√ |
2 | 數(shù)字類型 | number | [\d+.\d+] | 未區(qū)分浮點(diǎn)類型和整數(shù)類型 | √ |
3 | 字符串類型 | string | [char+] | 單、雙引號(hào)包裹 | √ |
4 | 數(shù)組類型 | array | [number...] | 必須指定數(shù)組類型,如 let arr:number[] = [1,2,3] , 第二種定義方式 let arr:Array<number> = [1,2] 泛型
|
√ |
5 | 元組類型 | tuple | 數(shù)組的一種,可以指定每個(gè)數(shù)組元素的類型 | let arr:[string, number, boolean] = ['ts', 3.18, true] |
√ |
6 | 枚舉類型 | enum | 事先考慮某個(gè)變量可能取得值 |
enum 枚舉名 { 標(biāo)識(shí)符[=整型常數(shù)], ... } ,類似C語言,其中值默認(rèn)為索引值, 示例: enum Flag {success=1, error} let f:Flag=Flag.success
|
√ |
7 | 任意類型 | any | 可以賦值為任意類型 | Object類型可以指定該類型 | × |
8 | null | null | 一個(gè)變量可以是基本數(shù)據(jù)類型,或者null或者undefined | let num:number / null |
× |
9 | undefined | undefined | 其他類型未初始化變量為undefined,但是引用會(huì)報(bào)錯(cuò);如果直接指定undefined沒有初始化就不會(huì)報(bào)錯(cuò) | let num:number / null / undefined |
× |
10 | 空類型 | void | 一般用于方法沒有返回值 | function run():void{} |
× |
11 | never類型 | never | 從來不會(huì)出現(xiàn) | let a:never a=(()=>{ throw new Error('錯(cuò)誤') })() |
× |
2.函數(shù)
- 函數(shù)的定義
· 函數(shù)參數(shù)指定類型,返回值指定類型- 函數(shù)聲明法
function run(name:string, age:number):void{ }
- 匿名函數(shù)法
· es5 實(shí)參和形參無需一樣,但是ts中必須一樣,如果不一樣需要配置可選參數(shù),let fun = function(name:string, age:number):void{ }
? 必須配置到后面,才能夠不混淆
· es5里面沒法設(shè)置默認(rèn)參數(shù),ts和es6都可以設(shè)置默認(rèn)參數(shù)let fun = function(name:string, age?:number):void{ // age 可傳可不傳 }
· 剩余參數(shù)[實(shí)參數(shù)量>形參數(shù)量]let fun = function(name:string, age:number=20):void{ // age 可傳可不傳,默認(rèn)為 20 } fun('zhangsan')
... 三點(diǎn)運(yùn)算符(es6)的使用let fun = function(...result:number[]):void{ // result 為數(shù)組類型使用 } fun(1, 2, 3, 4)
-
函數(shù)重載
java 中方法的重載指的是兩個(gè)或兩個(gè)以上同名函數(shù),但它們的參數(shù)不一樣,這時(shí)會(huì)出現(xiàn)函數(shù)重載的情況
ts 中重載指的是通過為同一個(gè)函數(shù)提供多個(gè)函數(shù)類型定義來實(shí)現(xiàn)多種功能的目的
ts 需要兼容 es5 和 es6 重載的寫法, 與 java 有區(qū)別function getInfo(str: string): string function getInfo(str: number): number function getInfo(str: any): any { if (typeof str === 'string') { return '我的名字是' + str } else { return '我的年齡是' + str } } console.log(getInfo('張三')) // 我的名字是張三 console.log(getInfo(20)) // 我的年齡是20
箭頭函數(shù) es6
() => {}
this 上下文指向函數(shù)運(yùn)行的上下文, 非私有
3.類(上) —— es5 中的類
-
Es5中的類和靜態(tài)方法
// 1. 最簡(jiǎn)單的類 - 通過構(gòu)造函數(shù) function Person() { this.name='張三'} var p = new Person() alert(p.name) // 2. 構(gòu)造函數(shù)和原型鏈增加屬性或者方法 // 區(qū)別: 實(shí)例不會(huì)共享構(gòu)造函數(shù)的屬性和方法, 原型鏈會(huì) function Person() { this.name='張三' this.run = function () { return this.name + '在奔跑' } } Person.prototype.work = function () { return this.name + '在工作' } var p = new Person() alert(p.run) alert(p.work) // 3. 類里面的靜態(tài)方法 // 實(shí)例方法必須 new 一個(gè)實(shí)例才可以使用,靜態(tài)相當(dāng)于默認(rèn)就有 Person.getInfo = function () { return '我是靜態(tài)方法' } alert(Person.getInfo())
-
Es5 繼承(原型鏈繼承、對(duì)象冒充繼承、原型鏈+對(duì)象冒充組合繼承)
- 對(duì)象冒充繼承
function Person() { this.name='張三' this.run = function () { return this.name + '在奔跑' } } Person.prototype.work = function () { return this.name + '在工作' } var p = new Person() // Web 類 繼承 Person 類 // 1. 對(duì)象冒充實(shí)現(xiàn)繼承 function Web() { Person.call(this) // 對(duì)象冒充實(shí)現(xiàn)繼承 } var w = new Web() console.info(w.run()) // 對(duì)象冒充可以繼承構(gòu)造函數(shù)的屬性和方法 // console.info(w.work()) // 但是無法繼承原型鏈上的屬性和方法
- 原型鏈繼承
function Person(name) { this.name = name this.run = function () { return this.name + '' } } Person.prototype.work = function () { return this.name + '在工作' } var p = new Person() // Web 類 繼承 Person 類 // 2. 原型鏈實(shí)現(xiàn)繼承 function Web(name) { } Web.prototype = new Person() var w = new Web() console.info(w.run()) // 可以繼承構(gòu)造函數(shù)的屬性和方法 undefined在奔跑 console.info(w.work()) // 可以繼承原型鏈上的屬性和方法 undefined在工作 // 問題: 實(shí)例化子類的時(shí)候,無法給父類傳參
- 原型鏈+對(duì)象冒充組合繼承
function Person(name) { this.name = name this.run = function () { return this.name + '在奔跑' } } Person.prototype.work = function () { return this.name + '在工作' } // 2. 原型鏈+對(duì)象冒充組合實(shí)現(xiàn)繼承 function Web(name) { Person.call(this, name) } Web.prototype = new Person() // 或者 Web.prototype = Person.prototype var w = new Web('zhangsan') console.info(w.run()) // 可以繼承構(gòu)造函數(shù)的屬性和方法 console.info(w.work()) // 可以繼承原型鏈上的屬性和方法
4.類(下) —— ts 中的類
-
類的定義
class
關(guān)鍵字class Person { name:string; // 屬性,前面省略了 public 關(guān)鍵字【默認(rèn)】 constructor(name:string) { // 構(gòu)造函數(shù),實(shí)例化類的時(shí)候觸發(fā)的方法 this.name = name } run():void { console.info(`${this.name}在跑步`) } } // 調(diào)用 let p = new Person('小張') p.run()
-
繼承
extends
關(guān)鍵字,super
關(guān)鍵字// 繼承 Person class worker extends Person { constructor(name:string){ super(name) } // 方法先看子類是否有,然后父類 } let w = new Web('李四') console.log(w.run())
類里面的修飾符 -
public,protected,private
public
: 公有 , 全都可以訪問【默認(rèn)】
protected
: 保護(hù) , 類和子類可以訪問
private
: 私有 , 類可以訪問
-
靜態(tài)屬性或者靜態(tài)方法 -
static
關(guān)鍵字class Person{ public name:string; static a:number = 0; constructor(name:string) { this.name = name } run ():void{ console.log(`${this.name}在奔跑`) } static print():void{ // 靜態(tài)方法無法直接調(diào)用類里的屬性 , static語法類似 C 語言 // 當(dāng)前類里面的全局存在 console.info(`靜態(tài)方法` + this.a++) } } Person.print()
-
抽象類 繼承 多態(tài)
-
多態(tài):父類定義一個(gè)方法不去實(shí)現(xiàn),讓繼承它的子類去實(shí)現(xiàn) , 每個(gè)子類根據(jù)自己的特性去定義不同的表現(xiàn)
多態(tài)屬于繼承class Animal { name: string constructor(name: string) { this.name = name } eat() { console.log('吃的方法') } work() { console.log('工作的方法') } } class Dog extends Animal { constructor(name: string) { super(name) } eat() { // this is 多態(tài) return '主人已經(jīng)準(zhǔn)備好狗糧,快來吃飯!' } }
-
抽象方法 - abstract 關(guān)鍵字
ts 中的抽象類,是提供其他類繼承的基類/父類,不能直接實(shí)例化
abstract
關(guān)鍵字來定義抽象類和抽象方法,抽象類中的抽象方法不包含具體實(shí)現(xiàn)并且必須在派生類中實(shí)現(xiàn)
作用: 抽象類和抽象方法用于定義標(biāo)準(zhǔn)// 定義animal子類必須包含eat方法 abstract class animal { // 抽象類 // 可以包含非抽象方法 work() { } abstract eat(): any; // 抽象方法, 抽象方法只能在抽象類中定義 }
-
5.接口
interface
關(guān)鍵字
接口的作用:
在面向?qū)ο蟮木幊讨校涌谑且环N規(guī)范的定義
它定義了行為和動(dòng)作的規(guī)范,起到限制和規(guī)范的作用。
接口定義了某類所需遵守的規(guī)范,不關(guān)注類的內(nèi)部狀態(tài)數(shù)據(jù),也不關(guān)注類里面方法的實(shí)現(xiàn)細(xì)節(jié),它只規(guī)定類里必須提供某些方法,提供方法的類就可以滿足實(shí)際需要。
ts 中的接口類似于 java, 同時(shí)還增加了更靈活的接口類型,包括屬性、函數(shù)、可索引和類等。
- 屬性類接口 —— 對(duì) json 的約束
function printLabel(labelInfo: { label: string }):void { // 對(duì)傳參 labelInfo 進(jìn)行了規(guī)定,必須要有 string類型的 label屬性 } // 對(duì)傳入對(duì)象的約束 : 屬性接口 interface Label { label: string; // 必須要有 label fontSize?: number; // 可選參數(shù),可傳可不傳 } // 規(guī)定形參 function print(label:Label):void { // console.info(label.name + label.name) // 語法報(bào)錯(cuò) // 需要嚴(yán)格遵守規(guī)則 } let obj = { name: 1, label: 'hah' } print(obj) // 可以有其他屬性 print({ label: 'jajja' }) // 只能有 label 屬性,否則報(bào)錯(cuò)
-
函數(shù)類型接口 : 對(duì)方法傳入的參數(shù) 以及返回值進(jìn)行 約束
// 加密的函數(shù)類型接口 interface encrypt { (key:string,value:string):string; } let md5: encrypt = function (k: string, v: string): string { return k + v; } console.log(md5('1', '2'))
- 可索引接口 : 數(shù)組、對(duì)象的約束(不常用)
// 對(duì)數(shù)組的約束 interface UserArr { [index: number]: string; // 索引值為 string 類型, index 為索引 } let arr: UserArr = ['aaa', 'bbb'] console.log(arr[0]) // 0 是指 index // 對(duì)對(duì)象的約束, 可索引接口 interface UserObj { [index: string]: number; // 索引值為 number 類型, index 為索引 } let obj1:UserObj = { name: 1, k: 2 } console.log(obj1.name) // name 是指 index
-
類類型接口: 對(duì)類的約束 和 抽象類有的相似
implements
關(guān)鍵字// 類類型接口: 對(duì)類的約束 和 抽象類有點(diǎn)相似 interface Animal2 { name: string; eat(): string; } class Dog1 implements Animal2 { name: string constructor(name: string) { // 構(gòu)造函數(shù) 初始化 name this.name = name } eat() { return `${this.name}在吃飯` } } let d1 = new Dog1('嘿嘿') console.log(d1.eat())
-
接口擴(kuò)展: 接口可以繼承接口
關(guān)鍵字interface
和extends
的合用// 接口擴(kuò)展:接口可以繼承接口 interface Animal3 { eat(): void; } interface Person1 extends Animal3 { work(): void; } class Programmer { name: string constructor(name: string) { this.name = name } coding() { return this.name + '在敲代碼中...' } } class Web implements Person1 { eat() {} work() {} } class Web1 extends Programmer implements Person1 { eat() {} work() {} } let web1 = new Web1('zhang') console.info(web1.coding())
6.泛型
泛型: 軟件工程中,我們不僅要?jiǎng)?chuàng)建一致的定義良好的API,同時(shí)也要考慮可重用性。
組件不僅能夠支持當(dāng)前的數(shù)據(jù)類型,同時(shí)也能支持未來的數(shù)據(jù)類型,這在創(chuàng)建大型系統(tǒng)時(shí)
為你提供了十分靈活的功能。
在 c# 或者 java 等語言中,可以使用泛型來創(chuàng)建可重用的組件,一個(gè)組件可以支持多種類型的數(shù)據(jù),方便用戶以自己的數(shù)據(jù)類型來使用組件
通俗理解: 泛型就是解決類、接口、方法的復(fù)用性、對(duì)不特定數(shù)據(jù)類型的支持
-
泛型函數(shù)/方法
// 泛型: 傳入類型靈活, 函數(shù)增強(qiáng)復(fù)用性, 拒絕不必要的冗余代碼 function getPerson(name: any): any { // any 類型 return name } getPerson(111) // T(任意字符) 表示類型,具體由方法調(diào)用的時(shí)候決定 function getPerson1<T>(name: T, key: string): any { // any 類型 console.log(name) return name + key } getPerson1<number>(111, 'aa') getPerson1<string>('ahhahah', 'aaa')
-
泛型類:
// 比如有個(gè)最小堆算法,需要同時(shí)支持返回?cái)?shù)字和字符串兩種類型 class MinClass<T>{ list: T[] = [] add(value: T): void { this.list.push(value) } min(): T { let minNum = this.list[0] for (let i = 0; i < this.list.length; i++) { if (minNum > this.list[i]) { minNum = this.list[i] } } return minNum } } let l1 = new MinClass<string>() l1.add('a') l1.add('b') l1.add('c') console.info(l1.min())
泛類:泛型可以避免重復(fù)的代碼以及對(duì)不特定的數(shù)據(jù)類型的支持(類型校驗(yàn)),下面我們把類當(dāng)做參數(shù)的泛型類
其可以去除重復(fù)代碼,可以對(duì)類型進(jìn)行校驗(yàn)/** * 1. 定義個(gè)類 * 2. 把類作為參數(shù)來約束數(shù)據(jù)傳入的類型 */ /** * 需求: * 1. 定義一個(gè) User 的類,作用是映射數(shù)據(jù)庫字段 * 2. 定義一個(gè) MysqlDb 的類,用于操作數(shù)據(jù)庫 * 3. 把 User 類作為參數(shù)傳入到 MysqlDb 中 * * ` 非常像 java 中的 dto 層 ` */ class User { username: string | undefined; password: string | undefined; } // 操作數(shù)據(jù)庫的泛型類 // 可以去除重復(fù)代碼,可以對(duì)類型進(jìn)行校驗(yàn) class MysqlDb<T> { list:T[] = [] // 模擬數(shù)據(jù)庫 constructor(l?: T[]) { if (l) { this.list = l } } add(user: T): boolean { this.list.push(user) console.log(user) return true } } var user1 = new User() user1.username = '張三' user1.password = '111' var mysql1 = new MysqlDb<User>() mysql1.add(user1)
NOTES:
- 語法和 java 大差不差 , 都是為了面向?qū)ο筮M(jìn)行服務(wù)
- 這種復(fù)用性又讓我想起了原生es5,原型鏈方法
-
泛型接口
interface ConfigFn{ <T>(value: T, key: string): T; } let getData: ConfigFn = function <T>(value: T, k: string): T { console.log(value + k) return value } getData<string>('hahha', 'hhah')
7. ts 中的類型、接口、類、泛型的綜合使用案例 —— ts 封裝統(tǒng)一操作 Mysql 、 Mongodb 、 Mssql 的底層庫
需求分析如下:
功能:定義一個(gè)操作數(shù)據(jù)庫的庫, 支持 Mysql Mssql Mongodb
要求1:Mysql Mssql Mongodb 功能一樣, 都有 增刪改查(add,update,delet,get)方法
注意:約束統(tǒng)一的規(guī)范,以及代碼重用
解決方案:需要約束規(guī)范所以要定義接口,需要代碼重用所以用到泛型
1. 接口: 在面向?qū)ο蟮倪^程中,接口是一種規(guī)范的定義,它定義了行為和動(dòng)作的規(guī)范
2. 泛型: 通俗理解,泛型就是提高 類、接口、方法的復(fù)用性
interface DBI<T>{
add(info: T): boolean;
update(info: T, id: number): boolean;
delete(id: number): boolean;
get(id: number): any[];
}
// 定義一個(gè)操作 mysql 數(shù)據(jù)庫的類 tip: 實(shí)現(xiàn)泛型接口 類也要是泛型類
class MySqlDb<T> implements DBI<T>{
add(info: T): boolean {
throw new Error("Method not implemented.");
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
class MsSqlDb<T> implements DBI<T>{
add(info: T): boolean {
throw new Error("Method not implemented.");
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
class MongoDb<T> implements DBI<T>{
add(info: T): boolean {
throw new Error("Method not implemented.");
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
// 操作用戶表 定義一個(gè) User 類和數(shù)據(jù)表做映射
class User {
id: number | undefined;
username: string | undefined;
password: string | undefined;
constructor(id: number, username: string, password: string) {
this.id = id
this.username = username
this.password = password
}
}
let u1 = new User(1, 'lily', '111111')
// let mMysql = new MySqlDb() // 沒有校驗(yàn)作用
let mMySql = new MySqlDb<User>() // 類作為參數(shù)來約束數(shù)據(jù)傳入的類型
mMySql.add(u1)
let mMsSql = new MsSqlDb<User>() // 類作為參數(shù)來約束數(shù)據(jù)傳入的類型
mMsSql.add(u1)
8. ts 模塊
js 模塊化 學(xué)習(xí)
ts 模塊的概念(官方):
· ts1.5發(fā)生了一些術(shù)語的變化,‘內(nèi)部模塊’ 稱為 ‘命名空間’
· ‘外部模塊’現(xiàn)在簡(jiǎn)稱為‘模塊’,模塊在其自身的作用域里執(zhí)行,而不是在全局作用域里,說明在一個(gè)模塊里的變量、函數(shù)、類等等在模塊外部不可見(不暴露、封裝性) ,除非 export
, 需要使用的時(shí)候使用 import
引入 export
暴露的方法、類、變量等等。
語法與 es6 相同
``` typescript
// index.ts 使用
import {User, UserModel} from './7-ts-modules/model/User'
import {Article, ArticleModel} from './7-ts-modules/model/Article'
/**
* 案例 之 7-ts 進(jìn)行模塊化
*/
var u = new User(1, 'lily', '111111')
UserModel.add(u)
var article = new Article(1, '特大新聞!特大新聞!今天有毛毛雨!', 'lily')
ArticleModel.add(article)
// db.ts
interface DBI<T>{
add(info: T): boolean;
update(info: T, id: number): boolean;
delete(id: number): boolean;
get(id: number): any[];
}
// 定義一個(gè)操作 mysql 數(shù)據(jù)庫的類 tip: 實(shí)現(xiàn)泛型接口 類也要是泛型類
export class MySqlDb<T> implements DBI<T>{
add(info: T): boolean {
console.info(info)
return true
}
update(info: T, id: number): boolean {
return true
}
delete(id: number): boolean {
return true
}
get(id: number): any[] {
return []
}
}
export class MsSqlDb<T> implements DBI<T>{
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number): boolean {
return true
}
delete(id: number): boolean {
return true
}
get(id: number): any[] {
return []
}
}
// User.ts
import {MySqlDb} from '../db/db'
class User {
id: number | undefined;
username: string | undefined;
password: string | undefined;
constructor(id: number, username: string, password: string) {
this.id = id
this.username = username
this.password = password
}
}
let UserModel = new MySqlDb<User>() // 類作為參數(shù)來約束數(shù)據(jù)傳入的類型
export { User, UserModel }
// 同理 > Article.ts
import {MsSqlDb} from '../db/db'
class Article {
id: number | undefined;
title: string | undefined;
author: string | undefined;
constructor(id: number, title: string, author: string) {
this.id = id
this.title = title
this.author = author
}
}
let ArticleModel = new MsSqlDb<Article>() // 類作為參數(shù)來約束數(shù)據(jù)傳入的類型
export { Article, ArticleModel }
```
引入其他模塊之后,編譯之后的文件路徑會(huì)有所變化
Notes:
- 可以感受到 ts 不僅可以用于 網(wǎng)頁, 還可以用于 大型程序多人開發(fā), nodejs環(huán)境...
- 其編程思想仍然更古不變,編程思想,設(shè)計(jì)模式很重要
9. 命名空間
定義:
代碼量較大的情況下,為了避免各種變量命名相沖突,可將相似功能的函數(shù)、類、接口等放置到命名空間內(nèi)
同 java 的包、.Net 的命名空間一樣, ts 的命名空間可以將代碼包裹起來,只對(duì)外暴露需要在外部訪問的對(duì)象。
命名空間內(nèi)的對(duì)象通過 export
暴露
與模塊的區(qū)別:
名稱 | 區(qū)分 |
---|---|
命名空間 | 內(nèi)部模塊,主要用于組織代碼,避免命名沖突 |
模塊 | ts 的外部模塊簡(jiǎn)稱,側(cè)重代碼的復(fù)用,一個(gè)模塊里可能會(huì)有多個(gè)命名空間 |
相同點(diǎn): 解決的都是代碼作用域的問題
利用 namespace
關(guān)鍵字:
``` typescript
namespace PersonA {
interface Animal {
name: string;
eat() : void;
}
export class Dog implements Animal {
name: string;
constructor(name:string) {
this.name = name
}
eat() {
console.log('小狗在吃飯')
}
export namespace H {
let name: string = 'jaj'
}
}
}
namespace PersonB {
}
let dog = new PersonA.Dog('花花')
dog.eat()
```
10. 裝飾器
定義:
裝飾器是一種特殊類型的聲明,它能夠被附加到類聲明、方法、屬性或參數(shù)上,可以修改類的行為。
通俗理解: 裝飾器是一個(gè)方法,可以注入到類、方法、屬性參數(shù)來擴(kuò)展他們的功能。
常見的裝飾器有: 類裝飾器、屬性裝飾器、方法裝飾器、參數(shù)裝飾器
裝飾器的寫法: 普通裝飾器(無法傳參)、裝飾器工廠(可傳參)
裝飾器是過去幾年中 js 最大的成就之一,已經(jīng)是 es7 的標(biāo)準(zhǔn)特性之一
-
類裝飾器: 在類聲明之前被聲明(緊靠著聲明)。
類裝飾器應(yīng)用于類構(gòu)造函數(shù),可以用來監(jiān)視、修改、替換類定義,傳入一個(gè)參數(shù)
es6 也有裝飾器 decorator{}- 普通方法(無法傳參)
function logClass(params: any) { console.info(params) // 當(dāng)前的類 params.url = 'hahha' params.prototype.Url = 'XXXX' params.prototype.run = function (): void { console.info('running....') } } @logClass class HttpClient1 { constructor() { } getData() { } } var http: any = new HttpClient1() console.log(http.url) // 無法獲取, undefined console.log(http.Url) http.run()
- 裝飾器工廠(可傳參)
// 2. 類裝飾器:裝飾器工廠(可傳參) namespace class2 { function logClass(params: string) { return function (target: any) { console.log(target) // 當(dāng)前的類 console.info(params) // 裝飾器傳入?yún)?shù) target.prototype.url = params target.prototype.run = function (): void { console.info('running....') } } } @logClass('http://xxx.com/api') class HttpClient1 { constructor() { } getData() { } } var http: any = new HttpClient1() console.log(http.url) http.run() }
- 類裝飾器替換類的構(gòu)造函數(shù)
function logClass(target: any) { return class extends target () { // 相當(dāng)于重寫,因?yàn)槊總€(gè)屬性都需要 extends constructor() { } getData() { } } } @logClass class HttpClient1 { constructor() { } getData() { } }
-
屬性裝飾器
都是語法糖function logClass (params: any){ return function (target: any, attr: any) { console.log(target) // 類 console.log(attr) // url target[attr] = params } } // @logClass('http://itying.com') // var url: any | undefined; // 無效 class ht1 { @logClass('http://itying.com') public url: any | undefined; } var t = new ht1() console.log(t.url)
-
方法裝飾器
方法裝飾器在運(yùn)行時(shí)傳入下列 3 個(gè)參數(shù):- 對(duì)于靜態(tài)成員來說是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象
- 成員的名字
- 成員的屬性描述符
跟 es6 的相似
// 方法裝飾器 function get(params: any) { return function (target: any, methodName: any, desc: any) { // console.log(target) // 對(duì)于靜態(tài)成員來說是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象 // console.log(methodName) // 成員的名字 // console.log(desc) // 成員的屬性描述符 // 修改裝飾器的方法, 把裝飾器方法里面?zhèn)魅氲乃袇?shù)改為 string 類型 // 1. 保存當(dāng)前的方法 let oMethod = desc.value // 保存當(dāng)前方法 // 修改當(dāng)前方法 desc.value = function (...args: any[]) { args = args.map((val) { return String(val) }) console.log('裝飾器中轉(zhuǎn)換的形參:' , args) oMethod.apply(this, args) // 融合類中的 該方法語句 } } } class Ht { url: string | undefined; constructor() { } @get('http://www.itying.com') getData(...args:any[]) { console.log(args) console.log('我是類中的方法') } } let ht = new Ht() ht.getData(12, 11, true)
-
參數(shù)裝飾器
不常用, 其他裝飾器也可以實(shí)現(xiàn)// 方法參數(shù)裝飾器 function logParams(params: any) { return function (target: any, methodName: any, paramsIndex: any) { console.log(target) console.log(methodName) console.log(paramsIndex) target.url = params } } class Ht { url: string | undefined; constructor() { } getCan(@logParams('uuid') uuid: any) { console.log(uuid) console.log('我是類中的參數(shù)方法') } } let ht = new Ht() ht.getCan('jjj') console.log(ht.url)
裝飾器順序:
順序 | 名稱 | 多個(gè)內(nèi)部順序 |
---|---|---|
1 | 屬性裝飾器 | |
2 | 方法裝飾器 | |
3 | 方法參數(shù)裝飾器 | 先執(zhí)行后面的,從后向前 |
4 | 類裝飾器 | 先執(zhí)行后面的,從后向前 |
四.案例 【 ts + angular 】
前提:
安裝angular/cli:
npm|cnpm install -g @angular/cli
驗(yàn)證:
ng version
新建項(xiàng)目:
ng new demo01
scss 和 sass 的區(qū)別:scss是sass的一個(gè)升級(jí)版本,完全兼容sass之前的功能,又有了些新增能力
- 文件擴(kuò)展名不同,sass是以“.sass”后綴為擴(kuò)展名,而SCSS是以“.scss”后綴為擴(kuò)展名。
- 語法不同,sass是以嚴(yán)格的縮進(jìn)式語法規(guī)則來書寫,而scss的語法與css語法非常相似。
運(yùn)行項(xiàng)目:
ng serve --open
來自b站視頻觀看筆記,有錯(cuò)請(qǐng)指正!!