主頁 > 企業開發 > JS 設計模式

JS 設計模式

2020-09-18 08:10:48 企業開發

面試敲門磚、進階墊腳石、設計有模式、代碼更合理

原始碼

  • 第1章 基礎知識
    • 1-1 Node.js 基礎知識
    • 1-2 TypeScript 基礎知識
  • 第2章 面向物件
    • 2-2 什么是面向物件
    • 2-3 面向物件-封裝
    • 2-4 面向物件-抽象
    • 2-5 面向物件-繼承
    • 2-6 面向物件-多型
    • 2-7 面向物件-總結
    • 2-8 UML圖-介紹
    • 2-9 UML類圖
  • 第3章 設計原則
    • 3-1 設計原則-介紹
    • 3-2 設計原則-何為設計
    • 3-3 設計原則-5大原則
      • 單一責任原則
      • 開放封閉原則
      • 里氏替換原則
      • 介面獨立原則
      • 依賴倒置原則
      • 設計原則總結
      • 用Promise來說明 S-O
    • 3-4 用promise演示
    • 3-5 設計模式簡介
    • 3-6 23種設計模式介紹
      • 創建型
      • 結構型
      • 行為型
      • 如何講解設計模式
    • 3-7 面試真題1
    • 3-8 面試真題2
    • 3-9 總結
  • 第4章 工廠模式
    • React.createElement
    • vue異步組件
    • 設計原則驗證
  • 第5章 單例模式
    • 示例
    • 設計 原則 驗證
  • 第6章 配接器模式
  • 第7章 裝飾器模式
  • 第8章 代理模式
    • 8-1 代理模式-介紹和演示
    • 8-2 代理模式-場景1(事件代理和jq的proxy)
    • 8-3 代理模式-場景2(明星經紀人)
    • 8-4 代理&配接器&裝飾模式對比
  • 第9章 外觀模式
    • 9-1 外觀模式
  • 第10章 觀察者模式
    • 10-1 觀察者模式-介紹和演示
    • 10-2 觀察者模式-場景1jquery
    • 10-3 觀察者模式-場景2NodeJs自定義事件
    • 10-4 觀察者模式-其它場景
  • 第11章 迭代器模式
    • 11-1 迭代器模式-介紹
    • 11-2 迭代器模式-演示
    • 11-3 迭代器模式-場景1(ES6 Iterator)
    • 11-4 迭代器模式-場景2
    • 11-5 迭代器模式-代碼演示和總結
  • 第12章 狀態模式
    • 12-1 狀態模式-介紹和演示
    • 12-2 狀態模式-場景1(有限狀態機)
    • 12-3 狀態模式-場景2(寫一個promise)
  • 第13章 其他設計模式
    • 13-1 其他設計模式概述
    • 13-2 原型模式
    • 13-3 橋接模式
    • 13-4 組合模式
    • 13-5 享元模式
    • 13-6 策略模式
    • 13-7 模板方法模式和職責連模式
    • 13-8 命令模式
    • 13-9 備忘錄模式
    • 13-10 中介者模式
    • 13-11 訪問者模式和解釋器模式
  • 第 14 章 推薦

第1章 基礎知識

1-1 Node.js 基礎知識

  • Node.js介紹
    • Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行時,
  • Node.js安裝
    • 常規Node.js 安裝配置
    • 版本管理:Node.js版本管理工具nvm
    • 版本管理:阿里Node.js版本管理工具
  • Node.js 入門
    • 七天學會NodeJS

1-2 TypeScript 基礎知識

  • TS 入門
    • TypeScript 教程

第2章 面向物件

2-2 什么是面向物件

  • 1. 什么是面向物件編程?
    • 面向物件編程是一種編程范式或編程風格,它以類或物件作為組織代碼的基本單元,并將封裝、抽象、繼承、多型四個特性,作為代碼設計和實作的基石 ,
  • 2. 什么是面向物件編程語言?
    • 支持類或物件的語法機制,并有現成的語法機制,能方便地實作面向物件編程四大特性(封裝、抽象、繼承、多型)的編程語言
  • 3. 如何判定一個編程語言是否是面向物件編程語言?
    • 嚴格:支持類、物件、四大特性
    • 寬泛:類、物件
  • 4. 面向物件編程和面向物件編程語言之間有何關系?
    • 面向物件編程不一定要用面向物件語言,使用面向物件語言寫出的代碼也不一定是面向物件語言的
  • 5. 什么是面向物件分析和面向物件設計?
    • 面向物件分析就是要搞清楚做什么,面向物件設計就是要搞清楚怎么做,
    • 產出是類圖

2-3 面向物件-封裝

  • 語法關鍵字:private、protected、public
  • 意義:
    • 保護資料不被隨意修改,提高代碼的可維護性
    • 僅暴露有限的必要介面,提高類的易用性,

2-4 面向物件-抽象

  • 講如何隱藏方法的具體實作
  • 意義:
    • 提高代碼的可擴展性、維護性,修改實作不需要改變定義,減少代碼的改動范圍
    • 處理復雜系統的有效手段,能有效地過濾掉不必要關注的資訊,

2-5 面向物件-繼承

  • 表示類之間的 is-a 關系
  • 單繼承和多繼承
  • 意義:解決代碼復用的問題,

2-6 面向物件-多型

  • 多型是指子類可以替換父類
  • 意義:提高代碼的擴展性和復用性

2-7 面向物件-總結

  • 面向物件編程有哪些優勢?
    • 更能應對這種復雜型別的程式開發
    • 更加豐富的特性(封裝、抽象、繼承、多型)
    • 易擴展、易復用、易維護,
    • 更加人性化、更加高級、更加智能,

2-8 UML圖-介紹

  • UML 中分9種圖:

    • 靜態模型圖: 描述系統的靜態結構

      • 類圖:顯示系統中的類, 介面以及它們之間的關系.

      • 物件圖:類圖的一個實體

      • 組件圖:各組件之間的關系

      • 部署圖:顯示軟體系統不同的組件將在何處物理地運行,以及它們將如何彼此通信

    • 動態模型圖: 描述系統的行為

      • 用例圖:從客戶的角度來描述系統功能

      • 活動圖(流程圖):描述系統的活動, 判定點和分支等.

      • 時序圖:描述物件之間訊息的傳遞時間順序

      • 協作圖:表達物件間的互動程序及物件間的關聯關系

      • 狀態圖:通過建立物件的生存周期模型來描述物件隨時間變化的動態行為

2-9 UML類圖

  • 類圖
    • 資料型別
      • + 表示 public,
      • 表示 private
      • # 表示 protected
      • ~ 表示 package

  • 介面的表示法(實線空心箭頭)

  • 類圖 中主要包括 4 種關系:

    • 泛化關系(繼承關系):實線空心箭頭
    • 實作關系(類與介面之間的實作關系):實線空心箭頭|虛線空心箭頭

    • 依賴關系:虛線的箭頭

    • 關聯關系

    • 聚合關系:空心菱形的實心線,菱形指向整體

      • 是整體與部分的關系,且部分可以離開整體而單獨存在
    • 組成關系:帶實心菱形的實線,菱形指向整體

      • 是整體與部分的關系,但部分不能離開整體而單獨存在

第3章 設計原則

3-1 設計原則-介紹

  • 即按照哪一種思路或者標準來實作功能
  • 功能相同,可以有不同的設計方案來實作
  • 伴隨著需求的增加,設計的作用才能體現出來

3-2 設計原則-何為設計

  • 設計準則:

    • 1 小既是美
    • 2 讓每個程式只做好一件事
    • 3 快速建立原型
    • 4 舍棄高效率而取可移植性
    • 5采用純文本來存盤資料
    • 6 充分利用軟體的杠桿效應(軟體復用)
    • 7 使用shell腳本來提高杠桿效應和可移植性
    • 8 避免強制性的用戶界面
    • 9 讓每一個程式都稱為過濾器
  • 小準則:

    • 允許用戶定制環境
    • 盡量使作業系統內核小而輕量化
    • 使用小寫字母并盡量簡短
    • 沉默是金
    • 各部分之和大于整體
    • 尋求 90% 的解決方案

源于:《UNIX/LINUX 設計思想》

3-3 設計原則-5大原則

S O L I D 五大設計原則
  • S - 單一責任原則
  • O - 開放封閉原則
  • L - 里氏替換原則
  • I - 介面獨立原則
  • D - 依賴倒置原則

單一責任原則

  • 一個程式只做好一件事
  • 如果功能過于復雜就拆分,每個部分保持獨立

開放封閉原則

  • 對擴展開發,對修改封閉
  • 增加需求時,擴展新代碼,而非修改已有代碼
  • 這個是軟體設計的終極目標

里氏替換原則

  • 子類能覆寫父類
  • 父類能出現的地方子類就能出現
  • JS中使用較少(弱型別&繼承使用較少)

介面獨立原則

  • 保持介面的單一獨立,避免出現 “胖介面”
  • JS中沒有介面(typescript例外),使用較少
  • 類似于單一職責原則,這里更關注介面

依賴倒置原則

  • 面向介面編程,依賴于抽象而不依賴于具體
  • 使用方只關注介面而不關注具體類的實作
  • JS中使用較少

設計原則總結

  • S O 體現較多,詳細介紹
  • LID 體現較少,但是要了解其用意

用Promise來說明 S-O

function loadImg(src) {
  var promise = new Promise(function(resolve, reject) {
    var img = document.createElement('img')
    img.onload = function () {
      resolve(img)
    }
    img.onerror = function () {
      reject('圖片加載失敗')
    }
    img.src = https://www.cnblogs.com/xulonglong/p/src
  })
  return promise
}

var src = 'https://img.uj5u.com/2020/09/18/818311808025921.png'
var result = loadImg(src)

result.then(function (img) {
  console.log('img.width', img.width)
  return img
}).then(function (img) {
  console.log('img.height', img.height)
}).catch(function (err) {
  console.error(err)
})
  • 單一職責原則:每個 then 中的邏輯只做好一件事
  • 開放封閉原則:如果新增需求,擴展then
  • 對擴展開發,對修改封閉

3-4 用promise演示

就是3-3的代碼

3-5 設計模式簡介

從設計到模式

體會什么是設計?設計是設計,模式是模式,兩者是分離的,

該如何學習設計模式?

  • 明白每個設計的道理和用意
  • 通過經典應用體會它的真正使用場景
  • 自己編碼時多思考,盡量模仿

3-6 23種設計模式介紹

其實設計模式大致分為三種型別:

  • 創建型
  • 組合型
  • 行為型

這23種設計模式分別分散在這三種型別中,

創建型

  • 工廠模式(工廠方法模式、抽象工廠模式、建造者模式)
    • 工廠模式是講怎么面向物件、怎么創建物件、怎么生成
  • 單例模式
    • 單例模式是講如果這個系統中只有一個指定物件,那么出現第二個時,該怎么辦
  • 原型模式
    • 原型模式是講如何通過一個現有的物件,用拷貝的方式來生成另一個新的物件

結構型

  • 配接器模式
  • 裝飾器模式
  • 代理模式
  • 外觀模式
  • 橋接模式
  • 組合模式
  • 享元模式

行為型

  • 策略模式
  • 模板方法模式
  • ★觀察者模式★
  • 迭代器模式
  • 職責鏈模式
  • 命令模式
  • 備忘錄模式
  • ★狀態模式★
  • 訪問者模式
  • 中介模式
  • 解釋器模式

如何講解設計模式

  • 介紹和舉例(生活中易理解的示例)
  • 畫UML類圖寫demo代碼
  • 結合經典應用場景,講解該設計模式如何被使用

3-7 面試真題1

  • 打車時,可以打專車或者快車,任何車都有車牌號和名稱
    • 決議:需設計公共父類(車牌號和名稱),父類下又有兩子類(專車和快車))
  • 不同車價格不同,快車每公里1元,專車每公里2元
    • 決議:子類里有不同的價格
  • 行程開始時,顯示車輛資訊
    • 行車和車有關系,但和專車還是快車沒關系,所以我們需要依賴抽象編程,所以行程只和車有關系,不和具體哪種車有關,也就是說無論什么車都有行車資訊
    • 所以我們需要再建一個"行程"的類,這個類參考車的某個屬性,我們可以通過這個屬性得到車的資訊(車牌號、名稱、單價)
  • 行程結束時,顯示打車金額(假定行程就5公里)
    • “金額”屬于行程,買了一萬輛車丟著是沒有行程金額的

UML類圖

uml01

class Car {
  constructor(number, name) {
    this.number = number
    this.name = name
  }
}

class Kuaiche extends Car {
  constructor(number, name) {
    super(number, name)
    this.Price = 1
  }
}

class Zhuanche extends Car {
  constructor(number, name) {
    super(number, name)
    this.Price = 2
  }
}

class Trip {
  constructor(car) {
    this.car = car
  }

  start() {
    console.log(`行程開始,名稱:${this.car.name},車牌號:${this.car.Price}`)
  }

  end() {
    console.log(`行程結束,價格:${this.car.Price * 5}`)
  }
}

let car = new Kuaiche('101', '捷達')
let trip = new Trip(car)
trip.start()
trip.end()

3-8 面試真題2

  • 某停車場,分3層,每層100車位
    • 決議:三個類,分別是停車場、每層、車位,三個class
  • 每個車位都能監控到車輛的駛入和離開
    • 決議:我們要給車位這個類定義一個方法或者屬性來監控車輛駛入和離開,這個監控的方法要改變車位這個類的一個狀態,車位空不空
  • 車輛進入前,顯示每層的空余車位數量
    • 決議:車輛進入前肯定面對的是停車場這個類,所以這個資訊要在停車場這個類中釋放出來,所以我們加一個方法,動態計算顯示每一層(每一層都是一個類的實體)空車位,所以層這個類里還得加顯示空車位的方法,最終由停車場這個類累加后顯示
  • 車輛進入時,攝像頭可以識別車牌號和時間
    • 決議:還得加攝像頭的class,這個class有方法能識別出車牌號和記錄駛入時間,也就是說攝像頭這個類,輸入的是車的實體,輸出車牌號和時間,這個車牌號和時間要讓停車場那個類里去存,所以停車場這個類還得加車輛串列的屬性
  • 車輛出來時,出口顯示幕顯示車牌號和停車時長
    • 決議:還得加顯示幕的類,通過顯示幕拿到車牌號和記錄的駛入時間,然后用當前時間減去這個事件就拿到了停車時長

uml02

// 車
class Car {
    constructor(num) {
        this.num = num
    }
}

// 入口攝像頭
class Camera {
    shot(car) {
        return {
            num: car.num,
            inTime: Date.now()
        }
    }
}

// 出口顯示幕
class Screen {
    show(car, inTime) {
        console.log('車牌號', car.num)
        console.log('停車時間', Date.now() - inTime)
    }
}

// 停車場
class Park {
    constructor(floors) {
        this.floors = floors || []
        this.camera = new Camera()
        this.screen = new Screen()
        this.carList = {}
    }
    in(car) {
        // 獲取攝像頭的資訊:號碼 時間
        const info = this.camera.shot(car)
        // 停到某個車位
        const i = parseInt(Math.random() * 100 % 100)
        const place = this.floors[0].places[i]
        place.in()
        info.place = place
        // 記錄資訊
        this.carList[car.num] = info
    }
    out(car) {
        // 獲取資訊
        const info = this.carList[car.num]
        const place = info.place
        place.out()

        // 顯示時間
        this.screen.show(car, info.inTime)

        // 洗掉資訊存盤
        delete this.carList[car.num]
    }
    emptyNum() {
        return this.floors.map(floor => {
            return `${floor.index} 層還有 ${floor.emptyPlaceNum()} 個車位`
        }).join('\n')
    }
}

// 層
class Floor {
    constructor(index, places) {
        this.index = index
        this.places = places || []
    }
    emptyPlaceNum() {
        let num = 0
        this.places.forEach(p => {
            if (p.empty) {
                num = num + 1
            }
        })
        return num
    }
}

// 車位
class Place {
    constructor() {
        this.empty = true
    }
    in() {
        this.empty = false
    }
    out() {
        this.empty = true
    }
}

// 測驗代碼------------------------------
// 初始化停車場
const floors = []
for (let i = 0; i < 3; i++) {
    const places = []
    for (let j = 0; j < 100; j++) {
        places[j] = new Place()
    }
    floors[i] = new Floor(i + 1, places)
}
const park = new Park(floors)

// 初始化車輛
const car1 = new Car('A1')
const car2 = new Car('A2')
const car3 = new Car('A3')

console.log('第一輛車進入')
console.log(park.emptyNum())
park.in(car1)
console.log('第二輛車進入')
console.log(park.emptyNum())
park.in(car2)
console.log('第一輛車離開')
park.out(car1)
console.log('第二輛車離開')
park.out(car2)

console.log('第三輛車進入')
console.log(park.emptyNum())
park.in(car3)
console.log('第三輛車離開')
park.out(car3)

3-9 總結

第4章 工廠模式

原理

  • new 操作單獨封裝
  • 遇到 new 時,就要考慮是否該使用工廠模式

示例

  • 你去購買漢堡,直接點餐、取餐,不會自己親手做
  • 商店要 “封裝” 做漢堡的作業,做好直接給顧客
/**
 * 工廠模式示例,邏輯如圖:
 *
 * --------------------------    ----------------|
 * |       Creator          |    |  Product      |
 * |------------------------|    |---------------|
 * |                        |    | + name:String |
 * |------------------------| -> |---------------|
 * | + create(name):Product |    | + init()      |
 * --------------------------    | + fn1()       |
 *                               | + fn2()       |
 *                               ----------------|
 */

class Product {
    constructor(name) {
        this.name = name;
    }

    init() {
        console.log("init", this.name);
    }

    fn1() {
        console.log("fn1", this.name);
    }

    fn2() {
        console.log("fn2", this.name);
    }
}

class Creator {
    create(name) {
        return new Product(name);
    }
}

// 測驗
const creator = new Creator();
const p1 = creator.create("test1");
const p2 = creator.create("test2");

p1.init();
p2.init();
p1.fn1();
p2.fn1();
p1.fn2();
p2.fn2();

場景

  • jQuery - $('div')
  • React.createElement
  • vue異步組件

React.createElement

react1

React.createElement使用工廠模式的好處:如果我們不用 createElement 封裝 new VNode(tag,attrs, children),在對生成VNode示例時我們還是讓用戶去驗證各個屬性引數,顯示不合理,而且用了工廠模式后用戶根本不關系內部建構式怎么變化,

vue異步組件

vue

Vue異步加載組件完成后創建組件的模式

使用工廠模式把工廠內部建構式與用戶隔離

設計原則驗證

  • 建構式和創建者分離
  • 符合開放封閉原則

第5章 單例模式

  • 系統中僅被唯一使用的
  • 一個類只有一個實體
/**
 * 單例模式
 */

class SingleObject {
    login() {
        console.log("login...");
    }
}

// 創建一個靜態自執行的方法
SingleObject.getInstance = (function() {
    let instance;
    return function() {
        if (!instance) {
            instance = new SingleObject();
        }

        return instance;
    }
})()


// 測驗
let obj1 = SingleObject.getInstance();
obj1.login();
let obj2 = SingleObject.getInstance();
obj2.login();

console.log(obj1 === obj2);

示例

  • 登錄框
class  LoginForm() {

    constructor() {
    
        this.state  =  'hide'
    
    }
    
    hide() {
    
        if(this.state  ===  'hide'){
        
            console.log('已經隱藏')
        
            return
        
        }
        
        this.state  ==  'hide'
        
        consoel.log('隱藏成功')
    
    }
    
    show() {
    
        if(this.state  ===  'show'){
        
            console.log('已經顯示')
            
            return
        
        }
        
        this.state  ===  'show'
        
        console.log('顯示成功')
    
    }

}

LoginForm.instance  = (function(){

    let  instance
    
    return  function(){
    
    if(!instance){
        instance  =  new  LoginForm()
    }
    
    return  instance

}

})()

let  login1  =  LoginForm.instance()

login1.hide()

let  login2  =  LoginForm.instance()

login2.hide()
  • 購物車
  • vuex和redux中的store

single

js-single

jQuery永遠只有一個

設計 原則 驗證

  • 符合單一職責原則,只實體化唯一的物件
  • 沒法具體開放封閉原則,但是絕對不違反開放封閉原則

第6章 配接器模式

  • 就介面格式和使用者不兼容
  • 中間加一個配接器介面

dd

d1

/**
 * 配接器模式
 */

class Adapter {
    specificRequest() {
        return "舊的介面內容"
    }
}

class Target {
    constructor() {
        this.adapter = new Adapter();
    }

    request() {
        let info = this.adapter.specificRequest();
        return `${info} - 處理... - 新的介面內容`;
    }
}

// 測驗
let target = new Target();
const r = target.request();
console.log(r);

場景

  • 封裝舊介面
  • Vue的computed

設計原則驗證

  • 將就借口和使用者進行分離
  • 符合開放封閉原則

第7章 裝飾器模式

  • 為物件添加新功能
  • 不改變其原有的結構和功能
  • 將現有物件和裝飾器進行分離,兩者獨立存在
/**
 * 裝飾器模式
 */

class Circle {
    draw() {
        console.log("畫一個圓");
    }
}

class Decorator {
    constructor(circle) {
        this.circle = circle;
    }

    draw() {
        this.circle.draw();
        this.setRedBorder(this.circle);
    }

    setRedBorder(circle) {
        console.log("設定紅色邊框");
    }
}

// 測驗
let c = new Circle();
c.draw();

let d = new Decorator(c);
d.draw();

第8章 代理模式

8-1 代理模式-介紹和演示

  • 使用者無權訪問目標物件
  • 中間加代理,通過代理做授權和控制
  • 代理類與目標類分離,隔離開目標類和使用者

8-2 代理模式-場景1(事件代理和jq的proxy)

8-3 代理模式-場景2(明星經紀人)

/**
 * 代理模式
 */

class ReadImg {
    constructor(filename) {
        this.filename = filename;
        this.loadFromDisk();
    }

    loadFromDisk() {
        console.log("從硬碟加載資料" + this.filename);
    }

    display() {
        console.log("顯示資料" + this.filename);
    }
}

class ProxyImg {
    constructor(filename) {
        this.realImg = new ReadImg(filename);
    }

    display() {
        this.realImg.display();
    }
}


// test
let proxyImg = new ProxyImg("1.png");
proxyImg.display();


// =================================

/**
 * 使用ES6語法的Proxy類演示 代理模式的示例,明星 - 經紀人
 */

let star = {
    name: "張xx",
    age : 25,
    phone: "138123456789"
}

let agent = new Proxy(star, {
    get: function(target, key) {
        if (key === "phone") {
            return "agent phone: 13555555555";
        }
        else if (key === "price") {
            return 150000;
        }
        return target[key];
    },
    set: function(target, key, val) {
        if (key === "customPrice") {
            if (val < 10000) {
                throw new Error("價格太低");
            } else {
                target[key] = val;
                return true;
            }
        }
    }
})

// test
console.log(agent.name);
console.log(agent.phone);
console.log(agent.age);
console.log(agent.price);

agent.customPrice = 120000; // OK
console.log(agent.customPrice);

agent.customPrice = 1000; // Error
console.log(agent.customPrice);

8-4 代理&配接器&裝飾模式對比

  • 代理模式VS配接器模式
    • 配接器模式:提供一個不同的介面(如不同版本的插頭)
    • 代理模式:提供一模一樣的介面
  • 代理模式VS裝飾器模式
    • 裝飾器模式:擴展功能,原有功能不變且可直接使用
    • 代理模式:顯示原有的功能,但是經過限制或者閹割之后的

第9章 外觀模式

9-1 外觀模式

  • 為子系統中的一組介面提供了一個高層介面
  • 使用者使用高層介面
  • 不符合單一職責原則和開放封閉原則,因此謹慎使用,不可濫用

第10章 觀察者模式

10-1 觀察者模式-介紹和演示

  • 發布 訂閱
  • 一對多
  • 主題和觀察者分離,不是主動觸發而是被動監聽,兩者解耦

10-2 觀察者模式-場景1jquery

10-3 觀察者模式-場景2NodeJs自定義事件

/**
 * 觀察者模式,使用nodejs的events模塊的示例
 */

const EventEmitter = require("events").EventEmitter;

// =========EventEmitter的基礎用法=============
const emitter1 = new EventEmitter();

// 監聽some事件
emitter1.on("some", info => {
    console.log("fn1", info);
})

// 監聽some事件
emitter1.on("some", info => {
    console.log("fn2", info);
})

// 觸發some事件
emitter1.emit("some", "xxxx");

// =============================================

// 下面使用繼承來實作EventEmitter
class Dog extends EventEmitter {
    constructor(name) {
        super();
        this.name = name;
    }
}

let dog = new Dog("dog");
dog.on("bark", function() {
    console.log(this.name, " barked-1");
})

dog.on("bark", function() {
    console.log(this.name, " barked-2");
})

setInterval(() => {
    dog.emit("bark")
}, 1000);

10-4 觀察者模式-其它場景

/**
 * 觀察者模式
 */

// 主題,保存狀態,狀態變化之后觸發所有觀察者物件
class Subject {
    constructor() {
        this.state = 0;
        this.observers = [];
    }

    getState() {
        return this.state;
    }

    setState(state) {
        this.state = state;
        this.notifyAllObservers();
    }

    notifyAllObservers() {
        this.observers.forEach(observer => {
            observer.update();
        })
    }

    attach(observer) {
        this.observers.push(observer);
    }
}

// 觀察者
class Observer {
    constructor(name, subject) {
        this.name = name;
        this.subject = subject;
        this.subject.attach(this);
    }

    update() {
        console.log(`${this.name} update! state is: ${this.subject.state}`);
    }
}


// 測驗
let s = new Subject();
let o1 = new Observer("o1", s);
let o2 = new Observer("o2", s);
let o3 = new Observer("o3", s);
let o4 = new Observer("o4", s);

s.setState(1);
s.setState(2);

第11章 迭代器模式

11-1 迭代器模式-介紹

  • 順序訪問一個集合
  • 使用者無需知道集合的內部結構(封裝)
  • 迭代器物件與目標物件分離
  • 迭代器將使用者與目標物件隔離開

11-2 迭代器模式-演示

11-3 迭代器模式-場景1(ES6 Iterator)

11-4 迭代器模式-場景2

11-5 迭代器模式-代碼演示和總結

/**
 * 迭代器模式
 */

class Iterator {
    constructor(container) {
        this.list = container.list;
        this.index = 0;
    }

    next() {
        if (this.hasNext()) {
            return this.list[this.index++];
        }
        return null;
    }

    hasNext() {
        if (this.index >= this.list.length) {
            return false;
        }
        return true;
    }
}

class Container {
    constructor(list) {
        this.list = list;
    }

    // 生成遍歷器
    getIterator() {
        return new Iterator(this);
    }
}


// 測驗
const arr = [1, 2, 3, 4, 5];
let container = new Container(arr);
let it = container.getIterator();
while(it.hasNext()) {
    console.log(it.next());
}

// ============= 使用ES6的迭代器生成 =============
function each(data) {
    // 生成遍歷器
    let it = data[Symbol.iterator]();

    let item;
    do {
        // 遍歷器生成可迭代內容,包含value和done屬性,
        // 其中done屬性代替自定義的hasNext()方法,
        // false表示還有資料,true則表示已經迭代完成
        item = it.next();
        if (!item.done) {
            console.log(item.value);
        }
    } while (!item.done);
}

// ES6的Iterator已經封裝在了語法 for...of 中,直接使用即可
function each2(data) {
    for (const item of data) {
        console.log(item);
    }
}


// 測驗
const arr2 = [10, 20, 30, 40, 50, 60];
let m = new Map();
m.set("a", 100);
m.set("b", 200);
m.set("c", 300);

each(arr2);
each(m);

each2(arr2);
each2(m);

第12章 狀態模式

12-1 狀態模式-介紹和演示

  • 允許一個物件在其內部狀態改變的時候改變它的行為,物件看起來似乎修改了它的類
/**
 * 狀態模式
 */

// 模擬紅綠燈狀態
class State {
    constructor(color) {
        this.color = color;
    }

    handle(context) {
        console.log(`切換到 ${this.color} `);
        context.setState(this);
    }
}

// 主體
class Context {
    constructor() {
        this.state = null;
    }

    getState() {
        return this.state;
    }

    setState(state) {
        this.state = state;
    }
}


// 測驗
let context = new Context();
let green = new State("綠燈");
let yellow = new State("黃燈");
let red = new State("紅燈");

// 綠燈亮
green.handle(context);
console.log(context.getState());
// 黃燈亮
yellow.handle(context);
console.log(context.getState());
// 紅燈亮
red.handle(context);
console.log(context.getState());

12-2 狀態模式-場景1(有限狀態機)

12-3 狀態模式-場景2(寫一個promise)

import * as fs from "fs";
import * as StateMachine  from 'javascript-state-machine';
import * as request from 'request';


// promise state: resolve(pending => fullfilled), reject(pending => rejected)
const fsm = new StateMachine({
  init: 'pending',
  transitions: [
    {
      name: 'resolve',
      form: 'pending',
      to: 'fullfilled'
    }, {
      name: 'reject',
      from: 'pending',
      to: 'rejected'
    }
  ],
  methods: {
    onResolve: function(state, data, data1) {
      // sate 當前狀態機實體;data fsm.resolve(xxx) 傳遞的引數
      // console.log(state, data)
      data.succFnList.forEach(fn => fn(data1));
    },
    onReject: function(state, data) {
      data.failFnList.forEach(fn => fn());
    }
  },

});


class MyPromise {

  succFnList: any[];
  failFnList: any[];

  constructor(fn) {
    this.succFnList = [];
    this.failFnList = [];

    fn((data) => {
      // resolve 函式
      fsm.resolve(this, data);
    },
    () => {
      // reject 函式
      fsm.reject(this);
    });
  }

  then(succFn, failFn) {
    this.succFnList.push(succFn);
    this.failFnList.push(failFn);
  }

}


function downloadImg(src) {
  const promise = new MyPromise(function(resolve, reject) {
    request(src, function(error, response, body) {
      if (error) {
        reject();
      }
      resolve(body);
    })
  });

  return promise;
}

const imgSrc = https://www.cnblogs.com/xulonglong/p/'https://www.npmjs.com/package/javascript-state-machine';

const imgPromise = downloadImg(imgSrc);
imgPromise.then(function(data) {
  console.log(fsm.state)
  fs.writeFileSync('./test.html', data)
}, function(error) {
  console.log(error);
});

第13章 其他設計模式

13-1 其他設計模式概述

13-2 原型模式

  • 原型模式(prototype)是指用原型實體指向創建物件的種類,并且通過拷貝這些原型創建新的物件,
/**
 * 原型模式
 * prototype可以理解為ES6中class的一種底層原理,但是class是實作面向物件的基礎,并不是服務于某個模式
 */

// 創建一個原型
let prototype = {
    getName: function() {
        return this.first + " " + this.last;
    },

    say: function() {
        console.log("Hello!");
    }
}

// 基于原型創建x
let x = Object.create(prototype);
x.first = "A";
x.last = "B";
console.log(x.getName());
x.say();

// 基于原型創建y
let y = Object.create(prototype);
y.first = "C";
y.last = "D";
console.log(y.getName());
y.say();

13-3 橋接模式

  • 橋接模式(Bridge)將抽象部分與它的實作部分分離,使它們都可以獨立地變化,
/**
 * 橋接模式
 */

class Color {
    constructor(name) {
        this.name = name;
    }
}

class Shape {
    constructor(name, color) {
        this.name = name;
        this.color = color;
    }

    draw() {
        console.log(`使用${this.color.name}顏色畫了一個${this.name}`);
    }
}


// 測驗
let red = new Color("red");
let yellow = new Color("yellow");
let circle = new Shape("circle", red);
circle.draw();

let triangle = new Shape("triangle", yellow);
triangle.draw();

13-4 組合模式

  • 將物件組合成樹形結構,以表示“整體-部分”的層次結構,
  • 通過物件的多型表現,使得用戶對單個物件和組合物件的使用具有一致性,
class TrainOrder {
    create () {
        console.log('創建火車票訂單')
    }
}
class HotelOrder {
    create () {
        console.log('創建酒店訂單')
    }
}

class TotalOrder {
    constructor () {
        this.orderList = []
    }
    addOrder (order) {
        this.orderList.push(order)
        return this
    }
    create () {
        this.orderList.forEach(item => {
            item.create()
        })
        return this
    }
}
// 可以在購票網站買車票同時也訂房間
let train = new TrainOrder()
let hotel = new HotelOrder()
let total = new TotalOrder()
total.addOrder(train).addOrder(hotel).create()

13-5 享元模式

  • 運用共享技術有效地支持大量細粒度物件的復用,系統只使用少量的物件,而這些物件都很相似,狀態變化很小,可以實作物件的多次復用,由于享元模式要求能夠共享的物件必須是細粒度物件,因此它又稱為輕量級模式,它是一種物件結構型模式
let examCarNum = 0         // 駕考車總數
/* 駕考車物件 */
class ExamCar {
    constructor(carType) {
        examCarNum++
        this.carId = examCarNum
        this.carType = carType ? '手動檔' : '自動檔'
        this.usingState = false    // 是否正在使用
    }

    /* 在本車上考試 */
    examine(candidateId) {
        return new Promise((resolve => {
            this.usingState = true
            console.log(`考生- ${ candidateId } 開始在${ this.carType }駕考車- ${ this.carId } 上考試`)
            setTimeout(() => {
                this.usingState = false
                console.log(`%c考生- ${ candidateId } 在${ this.carType }駕考車- ${ this.carId } 上考試完畢`, 'color:#f40')
                resolve()                       // 0~2秒后考試完畢
            }, Math.random() * 2000)
        }))
    }
}

/* 手動檔汽車物件池 */
ManualExamCarPool = {
    _pool: [],                  // 駕考車物件池
    _candidateQueue: [],        // 考生佇列

    /* 注冊考生 ID 串列 */
    registCandidates(candidateList) {
        candidateList.forEach(candidateId => this.registCandidate(candidateId))
    },

    /* 注冊手動檔考生 */
    registCandidate(candidateId) {
        const examCar = this.getManualExamCar()    // 找一個未被占用的手動檔駕考車
        if (examCar) {
            examCar.examine(candidateId)           // 開始考試,考完了讓佇列中的下一個考生開始考試
              .then(() => {
                  const nextCandidateId = this._candidateQueue.length && this._candidateQueue.shift()
                  nextCandidateId && this.registCandidate(nextCandidateId)
              })
        } else this._candidateQueue.push(candidateId)
    },

    /* 注冊手動檔車 */
    initManualExamCar(manualExamCarNum) {
        for (let i = 1; i <= manualExamCarNum; i++) {
            this._pool.push(new ExamCar(true))
        }
    },

    /* 獲取狀態為未被占用的手動檔車 */
    getManualExamCar() {
        return this._pool.find(car => !car.usingState)
    }
}

ManualExamCarPool.initManualExamCar(3)          // 一共有3個駕考車
ManualExamCarPool.registCandidates([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])  // 10個考生來考試

13-6 策略模式

  • 定義一系列的演算法,把它們一個個封裝起來,并且使它們可以互相替換
/**
 * 策略模式
 */

// 普通情況下,沒有使用策略模式
class User {
    constructor(type) {
        this.type = type;
    }

    buy() {
        if (this.type === "ordinary") {
            console.log("普通用戶購買");
        } else if (this.type === "member") {
            console.log("會員用戶購買");
        } else if (this.type === "vip") {
            console.log("高級會員購買");
        }
    }
}

// 使用
let u1 = new User("ordinary");
u1.buy();
let u2 = new User("member");
u2.buy();
let u3 = new User("vip");
u3.buy();


// ================ 使用策略模式進行調整 ===================
class OrdinaryUser {
    buy() {
        console.log("普通用戶購買");
    }
}

class MemberUser {
    buy() {
        console.log("會員用戶購買");
    }
}

class VipUser {
    buy() {
        console.log("高級會員用戶購買");
    }
}


// 測驗
let ou = new OrdinaryUser();
ou.buy();
let mu = new MemberUser();
mu.buy();
let vu = new VipUser();
vu.buy();

13-7 模板方法模式和職責連模式

/**
 * 職責鏈模式
 */

class Action {
    constructor(name) {
        this.name = name;
        this.nextAction = null;
    }

    setNextAction(action) {
        this.nextAction = action;
    }

    handle() {
        console.log(`${this.name} 執行了操作`);
        if (this.nextAction) {
            this.nextAction.handle();
        }
    }
}


// 測驗
let a1 = new Action("組長");
let a2 = new Action("經理");
let a3 = new Action("總監");
a1.setNextAction(a2);
a2.setNextAction(a3);
a1.handle();

13-8 命令模式

  • 將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日志,可以提供命令的撤銷和恢復功能,

/**
 * 命令模式
 */

class Receiver {
    exec() {
        console.log("執行");
    }
}

class Command {
    constructor(receiver) {
        this.receiver = receiver;
    }

    cmd() {
        console.log("觸發命令");
        this.receiver.exec();
    }
}

class Invoker {
    constructor(command) {
        this.command = command;
    }

    invoke() {
        console.log("開始");
        this.command.cmd();
    }
}


// 測驗
let soldier = new Receiver();
let trumpeter = new Command(soldier);
let general = new Invoker(trumpeter);
general.invoke();

13-9 備忘錄模式

  • 在不破壞封裝性的前提下,捕獲一個物件的內部狀態,并在該物件之外保存這個狀態,這樣以后就可將該物件恢復到保存的狀態,
/**
 * 備忘錄模式
 */

// 備忘類
class Memento {
    constructor(content) {
        this.content = content;
    }

    getContent() {
        return this.content;
    }
}

// 備忘串列
class CareTaker {
    constructor() {
        this.list = [];
    }

    add(memento) {
        this.list.push(memento);
    }

    get(index) {
        return this.list[index];
    }
}

// 編輯器
class Editor {
    constructor() {
        this.content = null;
    }

    setContent(content) {
        this.content = content;
    }

    getContent() {
        return this.content;
    }

    saveContentToMemento() {
        return new Memento(this.content);
    }

    getContentFromMemento(memento) {
        this.content = memento.getContent();
    }
}


// 測驗
let editor = new Editor();
let careTaker = new CareTaker();

editor.setContent("111");
editor.setContent("222");
careTaker.add(editor.saveContentToMemento()); // 備份
editor.setContent("333");
careTaker.add(editor.saveContentToMemento()); // 備份
editor.setContent("444");

console.log(editor.getContent());
editor.getContentFromMemento(careTaker.get(1)); // 撤銷
console.log(editor.getContent());
editor.getContentFromMemento(careTaker.get(0)); // 撤銷
console.log(editor.getContent());

13-10 中介者模式

  • 解除物件與物件之間的緊耦合關系,增加一個中介者物件后,所有的 相關物件都通過中介者物件來通信,而不是互相參考,所以當一個物件發生改變時,只需要通知 中介者物件即可,中介者使各物件之間耦合松散,而且可以獨立地改變它們之間的互動,中介者
    模式使網狀的多對多關系變成了相對簡單的一對多關系(類似于觀察者模式,但是單向的,由中介者統一管理,)
/**
 * 中介者模式
 */

class A {
    constructor() {
        this.number = 0;
    }

    setNumber(num, m) {
        this.number = num;
        if (m) {
            m.setB();
        }
    }
}

class B {
    constructor() {
        this.number = 0;
    }

    setNumber(num, m) {
        this.number = num;
        if (m) {
            m.setA();
        }
    }
}

class Mediator {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }

    setA() {
        let number = this.b.number;
        this.a.setNumber(number / 100);
    }

    setB() {
        let number = this.a.number;
        this.b.setNumber(number * 100);
    }
}


// 測驗
let a = new A();
let b = new B();
let m = new Mediator(a, b);
a.setNumber(100, m);
console.log(a.number, b.number);
b.setNumber(100, m);
console.log(a.number, b.number);

13-11 訪問者模式和解釋器模式

  • 訪問者模式: 給定一個語言, 定義它的文法的一種表示,并定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子,
class Context {
    constructor() {
      this._list = []; // 存放 終結符運算式
      this._sum = 0; // 存放 非終結符運算式(運算結果)
    }
  
    get sum() {
      return this._sum;
    }
    set sum(newValue) {
      this._sum = newValue;
    }
    add(expression) {
      this._list.push(expression);
    }
    get list() {
      return [...this._list];
    }
  }
  
  class PlusExpression {
    interpret(context) {
      if (!(context instanceof Context)) {
        throw new Error("TypeError");
      }
      context.sum = ++context.sum;
    }
  }
  class MinusExpression {
    interpret(context) {
      if (!(context instanceof Context)) {
        throw new Error("TypeError");
      }
      context.sum = --context.sum;
    }
  }
  
  /** 以下是測驗代碼 **/
  const context = new Context();
  
  // 依次添加: 加法 | 加法 | 減法 運算式
  context.add(new PlusExpression());
  context.add(new PlusExpression());
  context.add(new MinusExpression());
  
  // 依次執行: 加法 | 加法 | 減法 運算式
  context.list.forEach(expression => expression.interpret(context));
  console.log(context.sum);


第 14 章 推薦

  • B站:UML教程
  • 設計模式之美
  • B站:JS 設計模式教程
  • 《設計模式》
  • 《重構 2》

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/72149.html

標籤:JavaScript

上一篇:2020最新中級web前端面試題庫(含詳細答案,15k級別)你會幾道呢?

下一篇:HTML基礎標簽圖片文本超鏈接串列表格介紹

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more