原文地址:[Learning JavaScript Design Patterns]
前言
編寫可維護代碼很重要圈膏!好的設(shè)計模式可以幫助我們注意到代碼中重復(fù)出現(xiàn)的主題并對其進行優(yōu)化(更好地編寫可維護代碼)梭灿。
什么是模式曹铃?
設(shè)計模式是一種可重用的解決方案秸仙。在編寫應(yīng)用時飞蚓,可以在不同的情況下使用不同的設(shè)計模式來解決問題踱稍。
特性:
經(jīng)過驗證
易于重用
具有解釋性:用集合或者簡單的詞匯來描述復(fù)雜的解決方案
模式并不能解決所有的設(shè)計問題弟跑,但能提供很多優(yōu)勢:
有助于發(fā)現(xiàn)可能導(dǎo)致開發(fā)過程中出現(xiàn)重大問題的小問題
設(shè)計模式是通用的灾前,不同的編程語言都可以應(yīng)用來改進代碼結(jié)構(gòu)
方便開發(fā)人員交流
基于設(shè)計模式的解決方案比臨時解決方案更穩(wěn)定強大
測試、原型模式孟辑、三法則
測試:完整的模式是經(jīng)過嚴格審查和測試的
原型模式:尚未通過測試的模式哎甲,可能來自個人、社區(qū)
一個好的模式需要:
解決一個特定的問題
問題的解決方案不是顯而易見的(好的設(shè)計模式通常間接地為問題提供解決方案)[?]
所描述的概念必須是已經(jīng)被證明過的(設(shè)計模式需要證明它們的功能與描述的一致)
必須描述一種關(guān)系(設(shè)計模式需要描述深層次的系統(tǒng)結(jié)構(gòu)和機制與代碼的關(guān)系)
三法則:
模型如何被認為是成功的扑浸?(how/適合解決某種問題)
為什么模型被認為是成功的烧给?(why/對于目標是起作用的)
具有普遍的/廣泛的適用性
設(shè)計模式的結(jié)構(gòu)
一個設(shè)計模式應(yīng)該包括(設(shè)計自己的模式時):
名稱和描述
上下文大綱
問題陳述
解決方案
設(shè)計:包括與用戶的交互行為
執(zhí)行(操作)指南
可視化表示
示例/舉例
其他支持:包括其他模式
與其他模式的關(guān)系描述(借鑒/類似)
實際應(yīng)用
討論
編寫設(shè)計模式(pass)
現(xiàn)代JavaScript語法和特征
解耦應(yīng)用程序的重要性:模塊化可以使程序更容易維護
-
import、export:模塊化鼓勵代碼重用
.mjs is an extension used for JavaScript modules that helps us distinguish between module files and classic scripts (.js).
遠程加載模塊
-
動態(tài)導(dǎo)入:靜態(tài)導(dǎo)入需要先下載喝噪、執(zhí)行模塊圖后再運行代碼础嫡,這可能會導(dǎo)致初始頁面加載時間過長;按需加載可以提高初始加載時的性能
form.addEventListener("submit", e => { e.preventDefault(); import("/modules/cakeFactory.js") .then((module) => { // Do something with the module. module.oven.makeCupcake("sprinkles"); module.oven.makeMuffin("large"); }); }); let module = await import("/modules/cakeFactory.js");
服務(wù)器模塊:node 15.3.0開始支持js-modules(npm)
-
Classes With <u>Constructors, Getters & Setters</u>:
class Cake{ // We can define the body of a class" constructor // function by using the keyword "constructor" // with a list of class variables. constructor( name, toppings, price, cakeSize ){ this.name = name; this.cakeSize = cakeSize; this.toppings = toppings; this.price = price; } // As a part of ES2015+ efforts to decrease the unnecessary // use of "function" for everything, you'll notice that it's // dropped for cases such as the following. Here an identifier // followed by an argument list and a body defines a new method addTopping( topping ){ this.toppings.push( topping ); } // Getters can be defined by declaring get before // an identifier/method name and a curly body. get allToppings(){ return this.toppings; } get qualifiesForDiscount(){ return this.price > 5; } // Similar to getters, setters can be defined by using // the "set" keyword before an identifier set cakeSize( size ){ if ( size < 0){ throw "Cake must be a valid size - either small, medium or large"; } this._cakeSize = size;//寫成“cakeSize”會報錯“ Maximum call stack size exceeded” } } // Usage let cake = new Cake( "chocolate", ["chocolate chips"], 5, "large" ); // 繼承 class BirthdayCake extends Cake { surprise() { console.log(`Happy Birthday!`); } } let birthdayCake = new BirthdayCake( "chocolate", ["chocolate chips"], 5, "large" ); birthdayCake.surprise();
class Cookies { constructor(flavor) { this.flavor = flavor; } showTitle() { console.log(`The flavor of this cookie is ${this.flavor}.`); } } class FavoriteCookie extends Cookies { showTitle() { // super 調(diào)用父類的構(gòu)造函數(shù) super.showTitle(); console.log(`${this.flavor} is amazing.`); } } let myCookie = new FavoriteCookie('chocolate'); myCookie.showTitle();
class CookieWithPrivateField { // 創(chuàng)建私有類字段 #privateField; } class CookieWithPrivateMethod { #privateMethod() { return 'delicious cookies'; } }
Anti-Patterns
描述對導(dǎo)致不良情況發(fā)生的特定問題的<u>不良解決方案</u>
描述<u>如何擺脫上述情況</u>以及如何從那里找到一個好的解決方案
每個設(shè)計都始于努力去解決問題和其解決方案之間的適應(yīng)性。在程序投入生產(chǎn)并準備進入維護模式之后榴鼎,創(chuàng)建anti-patterns可以避免發(fā)生常見的錯誤伯诬,重構(gòu)代碼時可以使解決方案的整體質(zhì)量立即得到提高。
總而言之巫财,反模式是一個值得記錄的糟糕設(shè)計盗似。 JavaScript 中的反模式示例如下:
通過在全局上下文中定義大量變量來污染全局命名空間
將字符串而不是函數(shù)傳遞給 setTimeout 或 setInterval,因為這會在內(nèi)部觸發(fā) eval() 的使用
修改 Object 類原型
在內(nèi)聯(lián)表單中使用 JavaScript
嚴重濫用document.write平项,像 document.createElement 這樣的原生 DOM 替代品更合適