導(dǎo)航
[封裝-設(shè)計(jì)模式01] 設(shè)計(jì)原則 和 工廠模式(簡(jiǎn)單抽象方法) 適配器模式 裝飾器模式
[React 從零實(shí)踐01-后臺(tái)] 代碼分割
[React 從零實(shí)踐02-后臺(tái)] 權(quán)限控制
[React 從零實(shí)踐03-后臺(tái)] 自定義hooks
[React 從零實(shí)踐04-后臺(tái)] docker-compose 部署react+egg+nginx+mysql
[React 從零實(shí)踐05-后臺(tái)] Gitlab-CI使用Docker自動(dòng)化部署
[源碼-webpack01-前置知識(shí)] AST抽象語(yǔ)法樹(shù)
[源碼-webpack02-前置知識(shí)] Tapable
[源碼-webpack03] 手寫(xiě)webpack - compiler簡(jiǎn)單編譯流程
[源碼] Redux React-Redux01
[源碼] axios
[源碼] vuex
[源碼-vue01] data響應(yīng)式 和 初始化渲染
[源碼-vue02] computed 響應(yīng)式 - 初始化,訪問(wèn),更新過(guò)程
[源碼-vue03] watch 偵聽(tīng)屬性 - 初始化和更新
[源碼-vue04] Vue.set 和 vm.$set
[源碼-vue05] Vue.extend
[源碼-vue06] Vue.nextTick 和 vm.$nextTick
[部署01] Nginx
[部署02] Docker 部署vue項(xiàng)目
[部署03] gitlab-CI
[數(shù)據(jù)結(jié)構(gòu)和算法01] 二分查找和排序
[深入01] 執(zhí)行上下文
[深入02] 原型鏈
[深入03] 繼承
[深入04] 事件循環(huán)
[深入05] 柯里化 偏函數(shù) 函數(shù)記憶
[深入06] 隱式轉(zhuǎn)換 和 運(yùn)算符
[深入07] 瀏覽器緩存機(jī)制(http緩存機(jī)制)
[深入08] 前端安全
[深入09] 深淺拷貝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模塊化
[深入13] 觀察者模式 發(fā)布訂閱模式 雙向數(shù)據(jù)綁定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手寫(xiě)Promise
[深入20] 手寫(xiě)函數(shù)
[深入21] 數(shù)據(jù)結(jié)構(gòu)和算法 - 二分查找和排序
[深入22] js和v8垃圾回收機(jī)制
[深入23] JS設(shè)計(jì)模式 - 代理叉瘩,策略艘虎,單例
[前端學(xué)java01-SpringBoot實(shí)戰(zhàn)] 環(huán)境配置和HelloWorld服務(wù)
[前端學(xué)java02-SpringBoot實(shí)戰(zhàn)] mybatis + mysql 實(shí)現(xiàn)歌曲增刪改查
[前端學(xué)java03-SpringBoot實(shí)戰(zhàn)] lombok络它,日志诉瓦,部署
[前端學(xué)java04-SpringBoot實(shí)戰(zhàn)] 靜態(tài)資源 + 攔截器 + 前后端文件上傳
[前端學(xué)java05-SpringBoot實(shí)戰(zhàn)] 常用注解 + redis實(shí)現(xiàn)統(tǒng)計(jì)功能
[前端學(xué)java06-SpringBoot實(shí)戰(zhàn)] 注入 + Swagger2 3.0 + 單元測(cè)試JUnit5
[前端學(xué)java07-SpringBoot實(shí)戰(zhàn)] IOC掃描器 + 事務(wù) + Jackson
(一) 前置知識(shí)
(1) 一些單詞
principle 原則 原理
responsibility 職責(zé) 責(zé)任
substitution 代替 置換
// Single Responsibility Principle 單一職責(zé)原則
abstract 抽象的
simple 簡(jiǎn)單的
show up 出現(xiàn),露面
advanced 高級(jí)的殿怜,先進(jìn)的
configuration 配置
// advanced configuration 高級(jí)配置
constraint 約束
peek 偷看
shape 形狀
anonymous 匿名的
(2) Error
- new Error(message)
拋出Error實(shí)例對(duì)象后,整個(gè)程序就中斷在錯(cuò)誤發(fā)生的地方曙砂,不再往下執(zhí)行
- error實(shí)例屬性
- message 錯(cuò)誤提示信息
- name 錯(cuò)誤名稱(chēng) ( 非標(biāo)準(zhǔn)屬性 )
- stack 錯(cuò)誤堆棧 ( 非標(biāo)準(zhǔn)屬性 )
-
六種錯(cuò)誤對(duì)象
- SyntaxError 語(yǔ)法錯(cuò)誤
- ReferenceError ( 引用一個(gè)不存在的變量時(shí)發(fā)生的錯(cuò)誤 ) 或者 ( 將一個(gè)值分配給無(wú)法分配的對(duì)象 )
- RangeError 一個(gè)值超出有效范圍時(shí)發(fā)生的錯(cuò)誤
- TypeError ( 變量或者參數(shù) ) 不是 ( 預(yù)期類(lèi)型 ) 時(shí)候發(fā)生的錯(cuò)誤
- RUIError URI 相關(guān)函數(shù)的參數(shù)不正確時(shí)拋出的錯(cuò)誤
- EvalError eval函數(shù)沒(méi)有被正確執(zhí)行時(shí)拋出的錯(cuò)誤
- 第七種头谜,是自定義錯(cuò)誤對(duì)象
- 原理
- 1.就是普通的構(gòu)造函數(shù)(具有name,message麦轰,stack等屬性)
- 2.將構(gòu)造函數(shù)的prototype屬性指向 new Error() 生成的實(shí)例
- 3.將構(gòu)造函數(shù)的prototype.contructor屬性指向構(gòu)造函數(shù)自己乔夯,防止引用出錯(cuò)
- 原理
-
throw語(yǔ)句
- throw語(yǔ)句的作用是:手動(dòng)中斷程序執(zhí)行,并拋出錯(cuò)誤款侵,即手動(dòng)拋出錯(cuò)誤
- 注意:throw可以?huà)伋鋈我忸?lèi)型的值末荐,不一定是錯(cuò)誤實(shí)例
try { // throw new Error('錯(cuò)誤了') // ---------------------------- 注意:throw 可以?huà)伋鋈魏晤?lèi)型的值,不局限于錯(cuò)誤對(duì)象實(shí)例 throw '錯(cuò)誤了2' } catch(e) { // console.log(e.message) ----- 注意:這里對(duì)應(yīng)的是try拋出的錯(cuò)誤對(duì)象新锈,錯(cuò)誤對(duì)象具有message屬性 // ---------------------------- 注意:catch() 的參數(shù)是try代碼塊中拋出的值甲脏,即也可以是任意類(lèi)型 console.log(e); }
-
try...catch(e)結(jié)構(gòu)
- try...catch主要作用:是對(duì)錯(cuò)誤進(jìn)行處理,選擇是否往下執(zhí)行
- catch(e) 接受的參數(shù)表示try代碼塊拋出的值妹笆,任意類(lèi)型块请,因?yàn)閠hrow可以?huà)伋鋈我忸?lèi)型
- 注意:
catch捕獲錯(cuò)誤后,程序不會(huì)中斷拳缠,會(huì)按正常流程繼續(xù)執(zhí)行下去
try { throw "出錯(cuò)了"; } catch (e) { console.log(111); } console.log(222); // 111 // 222 還是會(huì)正常執(zhí)行
- try...catch還可以嵌套try...catch
-
try...finally結(jié)構(gòu)
- try...catch結(jié)構(gòu)允許在最后添加一個(gè)finally代碼塊墩新,表示不管是否出現(xiàn)錯(cuò)誤,都必需在最后運(yùn)行的語(yǔ)句
如果在try...catch中有return語(yǔ)句窟坐,會(huì)在finally執(zhí)行完畢后才會(huì)去執(zhí)行return后面的語(yǔ)句
(二) 六大設(shè)計(jì)原則
-
單一職責(zé)原則
Single Responsibility Principle -
開(kāi)放封閉原則
Open Closed Principle - 里氏替換原則 Liskov Substitution Principle
-
迪米特法則(最少知識(shí)原則)
Law of Demeter - 接口隔離原則 Interface Segregation Principle
- 依賴(lài)倒置原則 Dependence Inversion Principle
(2.1) 單一職責(zé)原則
- 關(guān)鍵詞
- (
單一
) (職責(zé)
) - 如果我們有兩個(gè)動(dòng)機(jī)去改寫(xiě)一個(gè)方法海渊,那么這個(gè)方法就具有兩個(gè)職責(zé)
- (
- 單一職責(zé)原則
- 一個(gè)方法只做一件事
- 這樣需求變遷,則只會(huì)影響到最小粒度的方法哲鸳,其他方法不會(huì)受到影響
-
如何劃分職責(zé)???
- 兩個(gè)完全不一樣的功能臣疑,不應(yīng)放在一個(gè)類(lèi)中
- 一個(gè)類(lèi)中應(yīng)該是 ( 一組相關(guān)性很高的函數(shù),或者數(shù)據(jù)的封裝 )
- 如果隨著需求的變化徙菠,有兩個(gè)職責(zé)總是同時(shí)變化讯沈,那就不必分離他們
- 即使兩個(gè)職責(zé)已經(jīng)被耦合在一起,但它們還沒(méi)有發(fā)生改變的征兆婿奔,那么也許沒(méi)有必要主動(dòng)分離它們
-
單一職責(zé)原則的優(yōu)優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn)
- 降低了單個(gè)類(lèi)或者對(duì)象的 ( 復(fù)雜度 )
- 按照 ( 職責(zé) ) 把類(lèi)和對(duì)象分解成 ( 更小粒度 )缺狠,有利于 ( 代碼復(fù)用 ) ( 單元測(cè)試 ) 等
- 當(dāng)一個(gè)職責(zé)變化時(shí)问慎,不會(huì)影響到其他職責(zé)
- 缺點(diǎn)
- 增加了代碼復(fù)雜度
- 增加了對(duì)象之間相互聯(lián)系的難度
- 優(yōu)點(diǎn)
(2.2) 開(kāi)放封閉原則
- 關(guān)鍵詞
-
開(kāi)放-封閉原則
,滿(mǎn)足類(lèi),對(duì)象,模塊长酗,函數(shù)是 (可擴(kuò)展的
)旋恼,但是是 (不可修改的
) - 即當(dāng)需要給程序添加功能或者修改功能時(shí),可以嘗試添加代碼,但是不能去修改源代碼
-
- 案例
- 用對(duì)象的 ( 多態(tài) ) 來(lái)消除 ( 條件分支 )
- 將 ( 穩(wěn)定不變的部分 ) 和 ( 容易變化的部分 ) 分開(kāi),則在系統(tǒng)演化迭代的過(guò)程中,只需要去修改經(jīng)常變化的部分挖腰,變化的部分使用 ( 鉤子函數(shù) ) 和 ( 回調(diào)函數(shù) )
- 優(yōu)點(diǎn)
- 原來(lái)的代碼不用修改
- 可以復(fù)用原來(lái)沒(méi)有修改的代碼
- 開(kāi)放封閉原則總結(jié)
- 不管是具體的各種設(shè)計(jì)模式,還是更抽象的面向?qū)ο笤O(shè)計(jì)原則练湿,比如單一職責(zé)原則猴仑、最少知識(shí)原則、依賴(lài)倒置原則等肥哎,都是為了讓程序遵守開(kāi)放-封閉原則而出現(xiàn)的
(2.3) 最少知識(shí)原則
- 概念
- 一個(gè) (
對(duì)象辽俗,類(lèi),模塊篡诽,函數(shù)崖飘,變量
) 等應(yīng)該對(duì)其他對(duì)象有最少的了解,減少對(duì)象之間的耦合
- 一個(gè) (
(2.4) 里氏替換原則
- 概念
- 所有引用 ( 基類(lèi) ) 的地方杈女,必須能夠使用其 ( 子類(lèi) ) 直接替換
- 特點(diǎn)
- 子類(lèi)必須實(shí)現(xiàn)父類(lèi)的所有方法朱浴,即繼承父類(lèi)所有的方法和屬性
- 子類(lèi)可以有自己的屬性和方法 ( 重寫(xiě)或者添加新的屬性 )
- 覆蓋或者實(shí)現(xiàn)父類(lèi)的方法時(shí),入?yún)⒖梢员环糯蟠镆敵隹梢员豢s小
(2.5) 依賴(lài)倒置原則
- 模塊間依賴(lài)通過(guò)抽象(比如:接口interface)發(fā)生翰蠢,實(shí)現(xiàn)類(lèi)(實(shí)現(xiàn)類(lèi)可以去實(shí)現(xiàn)接口中的方法)之間不直接依賴(lài)
- ( 實(shí)現(xiàn)類(lèi) ) 依賴(lài)于 ( 接口或抽象類(lèi) )
- ( 接口或者抽象類(lèi) ) 不依賴(lài)于 ( 實(shí)現(xiàn)類(lèi) ) - 什么是抽象類(lèi)類(lèi)?
- 什么是抽象類(lèi)類(lèi)啰劲?
- 如果以一個(gè)類(lèi)中沒(méi)有足夠的信息來(lái)描繪一個(gè)具體的對(duì)象梁沧,這樣的類(lèi)就是抽象類(lèi)
- 抽象類(lèi)不能實(shí)例化對(duì)象,所以抽象類(lèi)必須被繼承才能使用
(2.6) 接口隔離原則
- 客戶(hù)端不應(yīng)該依賴(lài)于它不需要的接口
- 建立單一的接口
(三) 工廠模式
(3.1) 簡(jiǎn)單工廠模式
在簡(jiǎn)單工廠模式中蝇裤,是由工廠來(lái)創(chuàng)建產(chǎn)品的趁尼,即是老板也是服務(wù)員
abstract class Animal { // 抽象類(lèi)不需要自己實(shí)現(xiàn)方法
constructor(public name: string) {
// this.name = name
}
}
class Cat extends Animal { } // 繼承
class Dog extends Animal { } // 繼承
// 簡(jiǎn)單工廠模式
// 通過(guò)傳入 (類(lèi)型) 在工廠類(lèi)中根據(jù)傳入的類(lèi)型,分別調(diào)用給構(gòu)造函數(shù)去生產(chǎn)對(duì)應(yīng)的實(shí)例
class AnimalFactory {
static create(name: string) { // static 靜態(tài)方法可以通過(guò)類(lèi)本身去調(diào)用
switch (name) { // 根據(jù)傳入的類(lèi)型猖辫,調(diào)用不同的構(gòu)造函數(shù),創(chuàng)建不同的實(shí)例
case 'cat':
return new Cat('cat')
case 'dog':
return new Dog('dog')
default:
return new Error('出錯(cuò)了')
}
}
}
const dog = AnimalFactory.create('dog') // 生產(chǎn)dog
const cat = AnimalFactory.create('cat') // 生產(chǎn)cat
console.log(dog)
console.log(cat)
(3.2) 工廠方法模式
- 在簡(jiǎn)單工廠模式中砚殿,是由工廠來(lái)創(chuàng)建產(chǎn)品的啃憎,即是老板也是服務(wù)員
在工廠方法模式中,不再由工廠來(lái)創(chuàng)建產(chǎn)品似炎,而是先創(chuàng)建具體的工廠辛萍,然后具體的工廠來(lái)創(chuàng)建產(chǎn)品
- 即由原來(lái)的老板做悯姊,變成了發(fā)命令讓別人來(lái)做
- 即由工廠命令其他工廠來(lái)生產(chǎn)產(chǎn)品
abstract class Animal { // ----------------------------------------- 產(chǎn)品
// 抽象類(lèi)不需要自己實(shí)現(xiàn)方法
constructor(public name: string) {
// this.name = name
}
}
class Cat extends Animal { } // ------------------------------------ 具體產(chǎn)品 cat
class Dog extends Animal { } // ------------------------------------ 具體產(chǎn)品 dog
abstract class AnimalFactory { // ---------------------------------- 具體類(lèi)型的工廠抽象類(lèi)
abstract createAnimal(): Animal
}
class CatFactory extends AnimalFactory { // ------------------------ 創(chuàng)建cat的工廠,實(shí)現(xiàn)類(lèi)
// 實(shí)現(xiàn)類(lèi) 實(shí)現(xiàn) 抽象類(lèi)的方法
createAnimal() {
return new Cat('cat')
}
}
class DogFactory extends AnimalFactory { // ------------------------ 創(chuàng)建dog的工廠贩毕,實(shí)現(xiàn)類(lèi)
// 實(shí)現(xiàn)類(lèi) 實(shí)現(xiàn) 抽象類(lèi)的方法
createAnimal() {
return new Dog('dog')
}
}
class Factory { // ------------------------------------------------- 工廠類(lèi)
// --------------------------------------------------------------- 根據(jù)類(lèi)型悯许,讓具體的工廠去生產(chǎn)產(chǎn)品
static create(name: string) { // static 靜態(tài)方法可以通過(guò)類(lèi)本身去調(diào)用
switch (name) { // 根據(jù)傳入的類(lèi)型,調(diào)用不同的構(gòu)造函數(shù)辉阶,創(chuàng)建不同的實(shí)例
case 'cat':
return new CatFactory().createAnimal()
case 'dog':
return new DogFactory().createAnimal()
default:
return new Error('出錯(cuò)了')
}
}
}
const dog = Factory.create('dog')
const cat = Factory.create('cat')
console.log(dog)
console.log(cat)
(3.3) 抽象工廠模式
abstract class Cat {}
abstract class Dog {}
class ChinessCat extends Cat {} // 中國(guó)貓
class ChinessDog extends Dog {} // 中國(guó)狗
class EnglishCat extends Cat {} // 美國(guó)貓
class EnglishDog extends Dog {} // 美國(guó)狗
abstract class AnimalFactory { // ------------------------------- 抽象工廠類(lèi) => 抽象動(dòng)物工廠
abstract createCat(): Cat
abstract createDog(): Dog
}
class ChineseAnimalFactory extends AnimalFactory { // ----------- 實(shí)現(xiàn)類(lèi) => 中國(guó)動(dòng)物工廠
createCat() {
return new ChinessCat()
}
createDog() {
return new ChinessDog()
}
}
class EnglishAnimalFactory extends AnimalFactory { // ----------- 實(shí)現(xiàn)類(lèi) => 美國(guó)動(dòng)物工廠
createCat() {
return new EnglishCat()
}
createDog() {
return new EnglishDog()
}
}
const chineseAnimal = new ChineseAnimalFactory() // ------------- 中國(guó)動(dòng)物
const chineseCat = chineseAnimal.createCat() // ----------------- 中國(guó)貓
console.log(chineseCat)
(四) 適配器模式 adapter
- 適配器模式又稱(chēng)包裝器模式先壕,將一個(gè)類(lèi)的接口轉(zhuǎn)化為用戶(hù)需要的另一個(gè)接口,解決類(lèi)或?qū)ο笾g接口不兼容問(wèn)題
- 舊的接口和使用者不兼容
- 中間加一個(gè)適配器轉(zhuǎn)換接口
- 總結(jié)
- 適配器模式就是為了解決 ( 適配兩個(gè)以上接口不兼容的問(wèn)題 ) 和 ( 外觀模式 ) 的核心思路保持一致
- 適配器模式adapter谆甜,也被稱(chēng)作 ( 包裝器模式wrapper )
- 本質(zhì)上是在原有邏輯上再包裝一層
- 類(lèi)比 ( 高階組件 )
1
// Rmb 是需要被適配的類(lèi)
class Rmb {
output() {
return '100rmb'
}
}
abstract class Money {
abstract transform(): string
}
class MoneyAdaptor extends Money { // 適配器實(shí)現(xiàn)類(lèi)
rmb: Rmb
constructor(rmb: Rmb) {
super()
this.rmb = rmb
}
transform() {
return this.rmb.output() + '轉(zhuǎn)成美元'
}
}
const dollar = new MoneyAdaptor(new Rmb())
console.log(dollar.transform());
2
適配器模式在javascript中的運(yùn)用
- 概念:適配器就是將不適配東西適配起來(lái)垃僚,比如:手機(jī)轉(zhuǎn)接頭,轉(zhuǎn)換器等
- 案例:將 ( 小寫(xiě)字符串 ) 適配成 ( 大寫(xiě)字符串 )
---
class Lower {
getSize = () => "size";
}
class Adapter {
lower = new Lower().getSize();
getSize = () => this.lower.toUpperCase(); // 轉(zhuǎn)成大寫(xiě)
}
const upper = new Adapter().getSize();
(4.1) 適配器模式有哪些運(yùn)用
- axios中區(qū)分瀏覽器和node端時(shí)的adaptor函數(shù)
- vue中的computed計(jì)算屬性
(4.2) 適配器模式應(yīng)用案例 - axios
- axios中的adapter函數(shù)就會(huì)根據(jù)系統(tǒng)的類(lèi)型去調(diào)用不同的請(qǐng)求方法规辱,比如瀏覽器中使用XMLHttpRequest谆棺,而在node環(huán)境中使用http模塊,從而抹平差異化
- axios源碼中的adapter
1. var adapter = config.adapter || defaults.adapter;
2. adapter(config).then() // 不管是什么環(huán)境罕袋,瀏覽器或者node都返回一個(gè)promise
3. defaultes.adapter 如下
var defaults = {
adapter: getDefaultAdapter()
}
function getDefaultAdapter() {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
adapter = require('./adapters/xhr'); // 瀏覽器環(huán)境
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
adapter = require('./adapters/http'); // node環(huán)境
}
return adapter;
}
手寫(xiě)一個(gè)axios中的adapter函數(shù)
axios({
method: "GET",
url: "www.baidu.com",
}).then(
(value) => console.log(value),
(reason) => console.error(reason)
);
// 設(shè)計(jì)模式y(tǒng)uanze
// 1. 單一職責(zé)原則 => 一個(gè)函數(shù)只實(shí)現(xiàn)一個(gè)邏輯
// 2. 開(kāi)放封閉原則 => 可擴(kuò)展改淑,不可修改
// 3. 最少知識(shí)原則 => 模塊,函數(shù)浴讯,方法朵夏,變量都要盡量依賴(lài)其他類(lèi)和對(duì)象
// 4. 里氏替換原則 => 基類(lèi)可以用子類(lèi)直接替換
// 5. 接口隔離原則
// 6. 依賴(lài)倒置原則 => 實(shí)現(xiàn)類(lèi) 依賴(lài) 接口或者抽象類(lèi)
// 瀏覽器端
function xhrAdaptor(config) {
const { method, url } = config;
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.setRequestHeader("Content-Type", "application/json"); // setRequestHeader 必須是在 open之后 send之前
xhr.responseType = "json";
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) {
return;
// readyState
// 0 UNSENT ------------- xhr實(shí)例已經(jīng)被創(chuàng)建,open()方法未被調(diào)用
// 1 OPEND -------------- open()方法被調(diào)用兰珍,send()方法未被調(diào)用侍郭,setRequestHeader() 可以被調(diào)用
// 2 HEADERS_RECEIVED --- send()方法被調(diào)用,響應(yīng)頭和響應(yīng)狀態(tài)已經(jīng)返回
// 3 LOADING ------------ 響應(yīng)體(response entity body)正在下載中掠河,此狀態(tài)下通過(guò) xhr.response 可能已經(jīng)有了響應(yīng)數(shù)據(jù)
// 4 DONE --------------- 整個(gè)數(shù)據(jù)傳輸過(guò)程已經(jīng)完成亮元,無(wú)論本次請(qǐng)求是成功還是失敗
}
if (xhr.status === 200) {
// readyState === 4 && status === 200
return resolve(xhr.responseText);
} else {
return reject(new Error(xhr.statusText));
}
};
xhr.onerror = function () {
console.error("error");
};
// xhr.onload = function() {
// if (xhr.status > 200 && xhr.status < 300 || xhr.status === 304) {
// return resolve(xhr.responseText)
// }
// }
xhr.send();
});
}
// 服務(wù)器端
function httpAdaptor(config) {
const { method, url } = config
const http = requrie('http')
const {hostname, port, path} = url.parse(url)
return new Promise((resolve, reject) => {
// http模塊
const options = {
method,
hostname,
port,
path
};
let req = http.request(options, function (response) {
let chunks = [];
response.on("data", function (chunk) {
chunks.push(chunk);
});
response.on("end", function () {
const result = Buffer.concat(chunks).toString();
return resolve(result);
});
});
req.on("error", function (error) {
return reject(error);
});
});
}
function getDefaultAdaptor() {
// ---------------------- 適配器模式,根據(jù)環(huán)境調(diào)用不同的方法
let adaptor;
if (typeof XMLHttpRequest !== "undefined") {
// ------ 瀏覽器環(huán)境
adaptor = xhrAdaptor;
}
if (typeof process !== "undefined") {
// ------------- node環(huán)境
adaptor = httpAdaptor;
}
return adaptor;
}
function axios(config) {
const adaptor = getDefaultAdaptor();
return adaptor(config);
// axios返回值就是一個(gè)promise對(duì)象唠摹,無(wú)論是瀏覽器端還是node端
}
(五) 裝飾器模式
- 裝飾器模式是為已有功能更多功能的一種方式爆捞,是一種結(jié)構(gòu)型設(shè)計(jì)模式,是對(duì)原有類(lèi)進(jìn)行擴(kuò)展
是一種依靠 ( 組合 ) 來(lái)實(shí)現(xiàn) ( 類(lèi)的功能擴(kuò)展 )勾拉,并且支 ( 持多層嵌套 ) 的設(shè)計(jì)模式
- 如果直接添加邏輯會(huì)違反 ( 單一職責(zé)原則 ) 和 ( 開(kāi)放封閉原則 )
- 常用的裝飾器有 ( 類(lèi)裝飾器 ) ( 屬性裝飾器 ) ( 方法裝飾器 ) ( 參數(shù)裝飾器 )
abstract class Shape { // 形狀抽象類(lèi)
abstract draw(): void;
}
class Circle extends Shape { // 形狀子類(lèi) 圓
draw() {
console.log("繪制圓");
}
}
class Rectagle extends Shape { // 形狀子類(lèi) 矩形
draw() {
console.log("繪制矩形");
}
}
abstract class Color extends Shape { // Color 也繼承 Shape
constructor(public shape: Shape) {
super();
}
abstract draw(): void;
}
class Red extends Color {
draw() {
this.shape.draw(); // 調(diào)用傳入的參數(shù)實(shí)例的draw方法煮甥,在new Red()時(shí)傳入的參數(shù)是new Circle()
console.log("繪制紅色");
}
}
class Yellow extends Color {
draw() {
this.shape.draw();
console.log("繪制黃色");
}
}
const redCircle = new Red(new Circle());
redCircle.draw() // 調(diào)用實(shí)例上的draw方法
(5.1) 裝飾器模式在前端中的運(yùn)用
2021/09/22 更新
- 表單驗(yàn)證
- 在 ( 表單提交時(shí),先做表單驗(yàn)證 ) 的工作
- 核心函數(shù):submit submit.before validate
/**
* 借助裝飾者模式藕赞,很容易衍生出 AOP 面向切面編程的概念
* - 場(chǎng)景:典型場(chǎng)景就是對(duì)表單的驗(yàn)證成肘,我們將把表單輸入邏輯校驗(yàn)的 validata 函數(shù)融入到 before 邏輯當(dāng)中
* - 具體:
* 1. 在提交表單時(shí),執(zhí)行 ( submit ) 函數(shù)斧蜕,因?yàn)樵?( Function.prototype.before ) 掛載了 ( before ) 函數(shù)双霍,被所有實(shí)例函數(shù)所繼承
* 2. 我們并不直接submit函數(shù),而是調(diào)用 ( submit.before ) 從而在 sumbit 之前執(zhí)行驗(yàn)證函數(shù) ( validate ) 從而在執(zhí)行sumbit之前做表單驗(yàn)證功能
*/
Function.prototype.before = function(beforefn) {
const self = this
return function() {
if (beforefn.apply(this, arguments) === false) return // 表示執(zhí)行驗(yàn)證邏輯時(shí),驗(yàn)證未通過(guò)
return self.apply(this, arguments) // this是調(diào)用before方法時(shí)所在的對(duì)象洒闸,是 submitBtn 在調(diào)用before染坯,所以在了的 self 就是 submitBtn 函數(shù)
}
}
const validate = function() {
// 表單驗(yàn)證邏輯
}
const formSubmit = function() {
// 表達(dá)提交邏輯
ajax('http:// xxx.com/login', param)
}
submitBtn.onclick = function() {
formSubmit.before(validate)
}
資料
設(shè)計(jì)原則1 https://juejin.cn/post/6844904025565970439
設(shè)計(jì)原則2 https://juejin.cn/post/6847902225717854215
裝飾器模式1 https://juejin.cn/post/6914235611545092109
裝飾器模式2 https://juejin.cn/post/6881897639001751560
vscode=>codeRunner=>ts-node出現(xiàn)亂碼解決方案如下
https://github.com/formulahendry/vscode-code-runner/issues/632