自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript 的 7 種設計模式

開發(fā) 前端
當啟動一個新的項目時候,我們不應該馬上開始編程。而是首先應該定義項目的目的和范圍,然后列出其功能或規(guī)格。如果你已經(jīng)開始編程或者正在從事一個復雜的項目,則應該選擇一個最適合你項目的設計模式。

 當啟動一個新的項目時候,我們不應該馬上開始編程。而是首先應該定義項目的目的和范圍,然后列出其功能或規(guī)格。如果你已經(jīng)開始編程或者正在從事一個復雜的項目,則應該選擇一個最適合你項目的設計模式。

[[382231]]

什么是設計模式?

在軟件工程中,設計模式是針對軟件設計中常見問題的可重用解決方案。設計模式也是經(jīng)驗豐富的開發(fā)人員針對特定問題的最佳實踐。它可以被當作編程的模板。

為什么要使用設計模式?

許多工程師要么認為設計模式浪費時間,要么不知道如何恰當?shù)氖褂迷O計模式。但如果能正確使用設計模式,則可以幫助你寫出更好的可讀性更高的代碼,并且代碼更容易被維護和理解。

最重要的是,設計模式為軟件開發(fā)人員提供了通用的詞匯表。它們能讓學習你代碼的人很快了解代碼的意圖。例如,如果你的項目中使用了裝飾器模式,那么新的開發(fā)可以很快就知道這段代碼的作用,從而他們可以將更多精力放在解決業(yè)務問題上,而不是試圖理解代碼在做什么。

我們已經(jīng)知道了什么是設計模式和它的重要性,下面我們深入研究一下 JavaScript 中的 7 種設計模式。

一、模塊模式

模塊是一段獨立的代碼,因此我們可以更新模塊而不會影響代碼的其它部分。模塊還允許我們通過為變量創(chuàng)建單獨的作用域來避免命名空間污染。當它們與其它代碼解耦時,我們還可以在其它項目中重用模塊。

模塊是任何現(xiàn)代 JavaScript 應用程序不可或缺的一部分,有助于保持代碼干凈,獨立和有條理。在 JavaScript 中有許多方法可以創(chuàng)建模塊,其中一種是模塊模式。

與其它編程語言不同,JavaScript 沒有訪問修飾符,也就是說,你不能將變量聲明為私有的或公共的。因此,模塊模式也可用來模擬封裝的概念。

模塊模式使用 IIFE(立即調用的函數(shù)表達式),閉包和函數(shù)作用域來模擬封裝的概念。例如:

 

  1. const myModule = (function() {   
  2.   const privateVariable = 'Hello World';   
  3.   function privateMethod() { 
  4.     console.log(privateVariable); 
  5.   } 
  6.   return { 
  7.     publicMethod: function() { 
  8.       privateMethod(); 
  9.     } 
  10.   } 
  11. })(); 
  12. myModule.publicMethod(); 

由于是 IIFE 因此代碼會被立即執(zhí)行,并將返回對象賦值給了 myModule 變量。由于閉包,即使在 IIFE 完成后,返回的對象仍可以訪問 IIFE 內部定義的函數(shù)和變量。

因此,IIFE 內部定義的變量和函數(shù)對外部是看不見的,從而使其成為 myModule 模塊的私有成員。

執(zhí)行代碼后,myModule 變量看起來像下面所示:

 

  1. const myModule = { 
  2.   publicMethod: function() { 
  3.     privateMethod(); 
  4.   }}; 

因此當我們調用 publicMethod() 時候,它將調用 privateMethod() 例如:

 

  1. // Prints 'Hello World' 
  2. module.publicMethod(); 

二、揭示模塊模式

揭示模塊模式是 Christian Heilmann 對模塊模式的略微改進。模塊模式的問題在于,我們必須創(chuàng)建新的公共函數(shù)才能調用私有函數(shù)和變量。

在這種模式下,我們將返回的對象的屬性映射到要公開暴露的私有函數(shù)上。這就是為什么將其稱為揭示模塊模式。例如:

 

  1. const myRevealingModule = (function() {   
  2.   let privateVar = 'Peter'
  3.   const publicVar  = 'Hello World'
  4.   function privateFunction() { 
  5.     console.log('Name: '+ privateVar); 
  6.   } 
  7.    
  8.   function publicSetName(name) { 
  9.     privateVar = name
  10.   } 
  11.   function publicGetName() { 
  12.     privateFunction(); 
  13.   } 
  14.   /** reveal methods and variables by assigning them to object     properties */ 
  15. return { 
  16.     setName: publicSetName, 
  17.     greeting: publicVar, 
  18.     getName: publicGetName 
  19.   }; 
  20. })(); 
  21. myRevealingModule.setName('Mark'); 
  22. // prints Name: Mark 
  23. myRevealingModule.getName(); 

這種模式讓我們更容易知道哪些函數(shù)和變量是公共的,無形中提高了代碼的可讀性。執(zhí)行代碼后 myRevealingModule 看起來像下所示:

 

  1. const myRevealingModule = { 
  2.   setName: publicSetName, 
  3.   greeting: publicVar, 
  4.   getName: publicGetName 
  5. }; 

當我們調用 myRevealingModule.setName('Mark') 時,實際調用了內部的 publicSetName。當調用 myRevealingModule.getName() 時,實際調用了內部的 publicGetName 例如:

 

  1. myRevealingModule.setName('Mark'); 
  2. // prints Name: Mark 
  3. myRevealingModule.getName(); 

與模塊模式相比,揭示模塊模式的優(yōu)勢有:

  • 通過修改 return 語句中的一行,我們可以將成員從公共變?yōu)闉樗饺耍粗嗳弧?/li>
  • 返回的對象不包含任何函數(shù)定義,所有右側表達式都在 IIFE 中定義,從而使代碼清晰易讀。

三、ES6 模塊

在 ES6 之前,JavaScript 沒有內置模塊,因此開發(fā)人員必須依靠第三方庫或模塊模式來實現(xiàn)模塊。但是自從 ES6,JavaScript 內置了模塊。

ES6 的模塊是以文件形式存儲的。每個文件只能有一個模塊。默認情況下,模塊內的所有內容都是私有的。通過使用 export 關鍵字來暴露函數(shù)、變量和類。模塊內的代碼始終在嚴格模式下運行。

3.1 導出模塊

有兩種方法可以導出函數(shù)和變量聲明:

  • 在函數(shù)和變量聲明的前面添加 export 關鍵字。例如:

 

  1. // utils.js 
  2. export const greeting = 'Hello World'
  3. export function sum(num1, num2) { 
  4.   console.log('Sum:', num1, num2); 
  5.   return num1 + num2; 
  6. export function subtract(num1, num2) { 
  7.   console.log('Subtract:', num1, num2); 
  8.   return num1 - num2; 
  9. // This is a private function 
  10. function privateLog() { 
  11.   console.log('Private Function'); 
  • 在代碼的最后添加 export 關鍵字來暴露函數(shù)和變量。例如:

 

  1. // utils.js 
  2. function multiply(num1, num2) { 
  3.   console.log('Multiply:', num1, num2); 
  4.   return num1 * num2; 
  5. function divide(num1, num2) { 
  6.   console.log('Divide:', num1, num2); 
  7.   return num1 / num2; 
  8. // This is a private function 
  9. function privateLog() { 
  10.   console.log('Private Function'); 
  11. export {multiply, divide}; 

3.2 導入模塊

與導出模塊相似,有兩種使用 import 關鍵字導入模塊的方法。例如:

  • 一次導入多個項目

 

  1. // main.js 
  2. // importing multiple items 
  3. import { sum, multiply } from './utils.js'
  4. console.log(sum(3, 7)); 
  5. console.log(multiply(3, 7)); 
  • 導入所有模塊

 

  1. // main.js 
  2. // importing all of module 
  3. import * as utils from './utils.js'
  4. console.log(utils.sum(3, 7)); 
  5. console.log(utils.multiply(3, 7)); 

3.3 導入導出中使用別名

  • 重命名導出

 

  1. // utils.js 
  2. function sum(num1, num2) { 
  3.   console.log('Sum:', num1, num2); 
  4.   return num1 + num2; 
  5. function multiply(num1, num2) { 
  6.   console.log('Multiply:', num1, num2); 
  7.   return num1 * num2; 
  8. export {sum as add, multiply}; 
  • 重命名導入

 

  1. // main.js 
  2. import { add, multiply as mult } from './utils.js'
  3. console.log(add(3, 7)); 
  4. console.log(mult(3, 7)); 

四、單例模式

一個單例對象是只能實例化一次的對象。如果不存在,則單例模式將創(chuàng)建類的新實例。如果存在實例,則僅返回對該對象的引用。重復調用構造函數(shù)將始終獲取同一對象。

JavaScript 是一直內置單例的語言。我們只是不稱它們?yōu)閱卫?,我們稱它們?yōu)閷ο笞置媪?。例如?/p>

 

  1. const user = { 
  2.   name'Peter'
  3.   age: 25, 
  4.   job: 'Teacher'
  5.   greet: function() { 
  6.     console.log('Hello!'); 
  7.   } 
  8. }; 

因為 JavaScript 中的每個對象都占用一個唯一的內存位置,并且當我們調用該 user 對象時,實際上是在返回該對象的引用。

如果我們嘗試將 user 變量復制到另一個變量并修改該變量。例如:

 

  1. const user1 = user
  2. user1.name = 'Mark'

我們將看到兩個對象都被修改,因為 JavaScript 中的對象是通過引用而不是通過值傳遞的。因此,內存中只有一個對象。例如:

 

  1. // prints 'Mark' 
  2. console.log(user.name); 
  3. // prints 'Mark' 
  4. console.log(user1.name); 
  5. // prints true 
  6. console.log(user === user1); 

可以使用構造函數(shù)來實現(xiàn)單例模式。例如:

 

  1. let instance = null
  2.  
  3. function User() { 
  4.   if(instance) { 
  5.     return instance; 
  6.   } 
  7.   instance = this; 
  8.   this.name = 'Peter'
  9.   this.age = 25; 
  10.    
  11.   return instance; 
  12. const user1 = new User(); 
  13. const user2 = new User(); 
  14. // prints true 
  15. console.log(user1 === user2); 

調用此構造函數(shù)時,它將檢查 instance 對象是否存在。如果對象不存在,則將 this 變量分配給 instance 變量。如果該對象存在,則只返回該對象。

單例也可以使用模塊模式來實現(xiàn)。例如:

 

  1. const singleton = (function() { 
  2.   let instance; 
  3.    
  4.   function init() { 
  5.     return { 
  6.       name'Peter'
  7.       age: 24, 
  8.     }; 
  9.   } 
  10.   return { 
  11.     getInstance: function() { 
  12.       if(!instance) { 
  13.         instance = init(); 
  14.       } 
  15.        
  16.       return instance; 
  17.     } 
  18.   } 
  19. })(); 
  20. const instanceA = singleton.getInstance(); 
  21. const instanceB = singleton.getInstance(); 
  22. // prints true 
  23. console.log(instanceA === instanceB); 

在上面的代碼中,我們通過調用 singleton.getInstance 方法來創(chuàng)建一個新實例。如果實例已經(jīng)存在,則此方法僅返回該實例。如果該實例不存在,則通過調用該 init() 函數(shù)創(chuàng)建一個新實例。

五、工廠模式

工廠模式使用工廠方法創(chuàng)建對象而不需要指定具體的類或構造函數(shù)的模式。

工廠模式用于創(chuàng)建對象而不需要暴露實例化的邏輯。當我們需要根據(jù)特定條件生成不同的對象時,可以使用此模式。例如:

 

  1. class Car{ 
  2.   constructor(options) { 
  3.     this.doors = options.doors || 4; 
  4.     this.state = options.state || 'brand new'
  5.     this.color = options.color || 'white'
  6.   } 
  7. class Truck { 
  8.   constructor(options) { 
  9.     this.doors = options.doors || 4; 
  10.     this.state = options.state || 'used'
  11.     this.color = options.color || 'black'
  12.   } 
  13. class VehicleFactory { 
  14.   createVehicle(options) { 
  15.     if(options.vehicleType === 'car') { 
  16.       return new Car(options); 
  17.     } else if(options.vehicleType === 'truck') { 
  18.       return new Truck(options); 
  19.       } 
  20.   } 

這里,創(chuàng)建了一個 Car 和一個 Truck 類(具有一些默認值),該類用于創(chuàng)建新的 car 和 truck對象。而且定義了一個VehicleFactory 類,用來根據(jù) options 對象中的 vehicleType 屬性來創(chuàng)建和返回新的對象。

 

  1. const factory = new VehicleFactory(); 
  2. const car = factory.createVehicle({ 
  3.   vehicleType: 'car'
  4.   doors: 4, 
  5.   color: 'silver'
  6.   state: 'Brand New' 
  7. }); 
  8. const truck= factory.createVehicle({ 
  9.   vehicleType: 'truck'
  10.   doors: 2, 
  11.   color: 'white'
  12.   state: 'used' 
  13. }); 
  14. // Prints Car {doors: 4, state: "Brand New", color: "silver"
  15. console.log(car); 
  16. // Prints Truck {doors: 2, state: "used", color: "white"
  17. console.log(truck); 

我為類 VehicleFactory 創(chuàng)建了一個新的 factory 對象。然后,我們通過調用 factory.createVehicle 方法并且傳遞 options 對象,其 vehicleType 屬性可能為 car 或者 truck 來創(chuàng)建新 Car 或 Truck 對象。

六、裝飾器模式

裝飾器模式用于擴展對象的功能,而無需修改現(xiàn)有的類或構造函數(shù)。此模式可用于將特征添加到對象中,而無需修改底層的代碼。

此模式的一個簡單示例為:

 

  1. function Car(name) { 
  2.   this.name = name
  3.   // Default values 
  4.   this.color = 'White'
  5. // Creating a new Object to decorate 
  6. const tesla= new Car('Tesla Model 3'); 
  7. // Decorating the object with new functionality 
  8. tesla.setColor = function(color) { 
  9.   this.color = color; 
  10. tesla.setPrice = function(price) { 
  11.   this.price = price; 
  12. tesla.setColor('black'); 
  13. tesla.setPrice(49000); 
  14. // prints black 
  15. console.log(tesla.color); 

這種模式的一個更實際的例子是:

假設汽車的成本取決于其功能的數(shù)量。如果沒有裝飾器模式,我們將不得不為不同的功能組合創(chuàng)建不同的類,每個類都有一個 cost 方法來計算成本。例如:

 

  1. class Car() { 
  2.  
  3. class CarWithAC() { 
  4.  
  5. class CarWithAutoTransmission { 
  6.  
  7. class CarWithPowerLocks { 
  8.  
  9. class CarWithACandPowerLocks { 

但是,通過裝飾器模式,我們可以創(chuàng)建一個基類 car 并且通過裝飾器函數(shù)給不同的對象添加對應的成本邏輯。

 

  1. class Car { 
  2.   constructor() { 
  3.   // Default Cost 
  4.   this.cost = function() { 
  5.   return 20000; 
  6.   } 
  7. // Decorator function 
  8. function carWithAC(car) { 
  9.   car.hasAC = true
  10.   const prevCost = car.cost(); 
  11.   car.cost = function() { 
  12.     return prevCost + 500; 
  13.   } 
  14. // Decorator function 
  15. function carWithAutoTransmission(car) { 
  16.   car.hasAutoTransmission = true
  17.    const prevCost = car.cost(); 
  18.   car.cost = function() { 
  19.     return prevCost + 2000; 
  20.   } 
  21. // Decorator function 
  22. function carWithPowerLocks(car) { 
  23.   car.hasPowerLocks = true
  24.   const prevCost = car.cost(); 
  25.   car.cost = function() { 
  26.     return prevCost + 500; 
  27.   } 

首先,我們創(chuàng)建了小轎車的基類 Car。然后針對要添加的特性創(chuàng)建了裝飾器并且此裝飾器以 Car 對象為參數(shù)。然后通過返回更新后的小汽車成本來覆蓋對象的成本函數(shù),且添加了一個用來標識某個特性是否已經(jīng)被添加的屬性。

要添加新的功能,我們只需要像下面一樣就可以:

 

  1. const car = new Car(); 
  2. console.log(car.cost()); 
  3. carWithAC(car); 
  4. carWithAutoTransmission(car); 
  5. carWithPowerLocks(car); 

最后,我們可以像這樣計算汽車的成本:

 

  1. // Calculating total cost of the car 
  2. console.log(car.cost()); 

結論

我們已經(jīng)了解了 JavaScript 中使用的各種設計模式,但是這里沒有涉及到可以用 JavaScript 實現(xiàn)的設計模式。

盡管了解各種設計模式很重要,但不要過度使用它們也同樣重要。在使用設計模式之前,你應該仔細考慮你的問題是否適合該設計模式。要知道某個模式是否適合你的問題,應該好好研究該設計模式以及它的應用。

責任編輯:華軒 來源: HelloGitHub
相關推薦

2023-05-15 15:29:13

設計模式JavaScript

2016-09-22 20:07:07

JavaScriptNode設計模式

2012-10-29 11:16:13

2023-11-02 21:11:11

JavaScript設計模式

2025-02-10 08:30:00

JavaScrip開發(fā)設計模式

2015-09-08 13:39:10

JavaScript設計模式

2012-12-25 09:38:41

JavaScript設計模式

2020-01-06 10:01:12

JavaScript瀏覽器HTML

2012-02-29 09:41:14

JavaScript

2020-10-09 06:52:31

設計模式軟件

2020-10-14 13:58:14

23種設計模式速記

2015-09-14 09:31:44

結對設計

2009-06-29 18:11:40

JSP設計模式

2009-01-04 13:49:17

Java設計模式設計模式工廠模式

2023-09-22 11:58:49

2009-06-15 14:15:07

Java設計模式Java

2024-05-30 08:01:52

2022-05-27 11:33:02

前端代碼設計模式

2011-09-01 13:51:52

JavaScript

2021-04-09 20:38:20

Vue模式.前端
點贊
收藏

51CTO技術棧公眾號