Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 在线视频久久,天天干天天操天天插,国产亚洲视频在线

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          html基礎-2

          ody

          常用標簽

          body分為塊級和行內

          • 塊級 獨占整行
          • 行內 內容有多少就占多少

          文本格式化標簽

          br 換行

          <div>qwer<br/>zxcv</div>

          div和span

          • div 塊級標簽樣式
          <div style="background-color: green;">qwer</div>
          • span 行內標簽樣式
          span style="background-color: green;">zxcv</span>

          p 段落

          <p>hahahahah</p> 
          <p>hahahahahaaa</p>   

          h 標題

          h1~h6y依次變小

             <div>默認文字字體</div>
             <h1>再再再再再粗一點</h1>
             <h2>再再再再粗一點</h2>
             <h3>再再再粗一點</h3>
             <h4>再再粗一點</h4>
             <h5>再粗一點</h5>
             <h6>粗一點</h6>
          

          鏈接

          • a 超鏈接,跳轉到指定的地址
          <a href="http://www.baidu.com" title="baidu">百度</a>
          • 錨點,點擊后跳轉到指定位置
          <!DOCTYPE html>
          <html lang="en">
          <head>
             <meta charset="UTF-8">
             <title>野雞平臺</title>
          </head>
          <body>
          <h1>章節</h1>
          <a href="#i1" title="第一章">第一章 寂寞的春天</a>
          <a href="#i2" title="第二章">第二章 寂寞的夏天</a>
          <a href="#i3" title="第三章">第三章 寂寞的秋天</a>
          <a href="#i4" title="第四章">第四章 寂寞的冬天</a>
          <h1>內容</h1>
          <div style="height: 1000px;" id="i1">
             <h3>第一章 寂寞的春天</h3>
             <p>春暖花開,萬物復蘇,又到了交配的季節。</p>
          </div>
          <div style="height: 1000px;" id="i2">
             <h3>第二章 寂寞的夏天</h3>
             <p>夏天夏天悄悄過去留下小咪咪</p>
          </div>
          <div style="height: 1000px;" id="i3">
             <h3>第三章 寂寞的秋天</h3>
             <p>今年的秋天真是寂寞呀!!!</p>
          </div>
          <div style="height: 1000px;" id="i4">
             <h3>第四章 寂寞的冬天</h3>
             <p>下雪</p>
          </div>
          </body>
          </html>
          

          ul ol dl 列表展示

          • ul 無序列表
          • ol 有序列表
          • dl 層級列表
          • li 列表項目
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>野雞平臺</title>
          </head>
          <body>
              <ul>
                  <li>周杰倫</li>
                  <li>林俊杰</li>
                  <li>王力宏</li>
              </ul>
              <ol>
                  <li>鐵錘</li>
                  <li>鋼彈</li>
                  <li>狗蛋</li>
              </ol>
              <dl>
                  <dt>河北省</dt>
                  <dd>邯鄲</dd>
                  <dd>石家莊</dd>
                  <dt>山西省</dt>
                  <dd>太原</dd>
                  <dd>平遙</dd>
              </dl>
          </body>
          </html>
          

          table 表格

          • table表格標題
          • thead表格標題
          • tr 行標簽
          • th 列名
          • tbody表格內容
          • tr 列標簽
          • td 列內容
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>6666</title>
          </head>
          <body>
              <table border="3">   <!--border 選擇表格樣式-->>
                  <thead>
                      <tr>
                          <th>姓名</th>
                          <th>年齡</th>
                          <th>愛好</th>
                      </tr>
                  </thead>
                  <tbody>
                      <tr>
                          <td>xxxx</td>
                          <td>18</td>
                          <td>看書</td>
                      </tr>
                      <tr>
                          <td rowspan="3">aaaa</td>  <!--rowspan 合并單元格-->>
                          <td>18</td>
                          <td>吃飯</td>
                      </tr>
                      <tr>
                          <td>33</td>>
                          <td>heiheihei</td>>
                      </tr>>
                  </tbody>
              </table>
          </body>
          </html>
          

          img 圖片

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>6666</title>
          </head>
          <body>
              <!--顯示本地圖片,找不到圖片則顯示alt中的文字-->
              <img src="img/lover.png" alt="美女">
              <!--顯示網絡圖片-->
              <img src="https://images.cnblogs.com/cnblogs_com/wupeiqi/662608/t_212313579359018.png" alt="妹子">
          </body>
          </html>
          

          用戶交互

          按鈕標簽

          type

          • buttom: 普通
          • submit: 提交
          • reset: 重置
           <button type="button"> 按鈕 </button>

          input

          • text,文本框。
          • password,密碼框。
          • radio,單選框(必須設置name屬性相同,否則無法實現)。
          • checkbox,復選框。
          • file,文件上傳。
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>666666</title>
          </head>
          <body>
              <h3>文本框</h3>
              <input type="text">
              <h3>密碼框</h3>
              <input type="password">
              <h3>單選框</h3>
              <input type="radio" name="gender">男
              <input type="radio" name="gender">女
              <h3>復選框</h3>
              <input type="checkbox">籃球
              <input type="checkbox">足球
              <input type="checkbox">橄欖球
              <h3>上傳文件</h3>
              <input type="file">
          </body>
          </html>

          select下拉框

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>HTML學習</title>
          </head>
          <body>
              <h3>單選</h3>
              <select>
                  <option>上海</option>
                  <option>北京</option>
                  <option>深圳</option>
              </select>
              <h3>多選</h3>
              <select multiple>
                  <option>上海</option>
                  <option>北京</option>
                  <option>深圳</option>
              </select>
          </body>
          </html>

          textarea多行文本框

          <!DOCTYPE html>
          臥槽,無情呀
          <html lang="en">
          <head>
              <meta charset="UTF-8" />
              <title>HTML學習</title>
          </head>
          <body>
              <textarea>文本內容寫在這里...</textarea>
          </body>
          </body>
          </html>

          form表單

          用于提交數據到后臺

          • 提交時,只會提交form標簽內部【用戶交互】相關的標簽。
          • <input type="submit" value="提交"> 用于提交當前所在的表單。
          • <input type="reset" value="重置"> 用于重置當前標簽中的選項。
          • form標簽內置屬性action="/xx/" ,表示表單要提交的地址。method="get",表示表單的提交方式。enctype="multipart/form-data",如果form內部有文件上傳,必須加上此設置
          • form內部【用戶交互】相關標簽必須設置name,不然提交數據后后端無法獲取
          // 提交表單之后,實際上會將表單中的數據構造成一種特殊的結構,發送給后臺,類似于:
          {
              user:用戶輸入的姓名,
            pwd:用戶輸入的密碼,
              ...
          }
          
          • radio、checkbox、select 除了要設置name屬性以外,還必須設置value屬性,因為這三中標簽在form表單提交時,不會把看到的內容提交到后臺,而是把選擇選項對應的value值提交到后臺。

          <script src="https://lf3-cdn-tos.bytescm.com/obj/cdn-static-resource/tt_player/tt.player.js?v=20160723"></script>

          序列定義:

          文字前面的符號或者序列

          特點:

          塊元素 ,獨立成行,行間距 , 行縮進

          類別:

          包括兩種,一種是有序的叫ol,一種是無序的ul

          兩者共同點:

          這兩個都同樣嵌套li。

          無序標簽屬性 :

          type disc 實心圓(默認屬性) circle空心圓 square實心四方

          有序標簽屬性:

          type =1 a A i I

          start="n"從第n個數開始計數

          嵌套關系,UL可以嵌套UL,原則是繼續縮進

          部分講設計模式的文章都是使用的JavaC++這樣的以類為基礎的靜態類型語言,作為前端開發者,js這門基于原型的動態語言,函數成為了一等公民,在實現一些設計模式上稍顯不同,甚至簡單到不像使用了設計模式,有時候也會產生些困惑。
          設計模式 Design Pattern 是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結,使用設計模式是為了可重用代碼、讓代碼更容易被他人理解并且保證代碼可靠性。

          為什么要學習設計模式:

          • 設計模式來源眾多專家的經驗和智慧,它們是從許多優秀的軟件系統中總結出的成功的、能夠實現可維護性、復用的設計方案,使用這些方案將可以讓我們避免做一些重復性的工作
          • 設計模式提供了一套通用的設計詞匯和一種通用的形式來方便開發人員之間溝通和交流,使得設計方案更加通俗易懂
          • 大部分設計模式都兼顧了系統的可重用性和可擴展性,這使得我們可以更好地重用一些已有的設計方案、功能模塊甚至一個完整的軟件系統,避免我們經常做一些重復的設計、編寫一些重復的代碼
          • 合理使用設計模式并對設計模式的使用情況進行文檔化,將有助于別人更快地理解系統
          • 學習設計模式將有助于初學者更加深入地理解面向對象思想

          JavaScript 中常見設計模式

          設計模式分類(23種設計模式)

          創建型

            • 單例模式
            • 原型模式
            • 工廠模式
            • 抽象工廠模式
            • 建造者模式

          結構型

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

          行為型

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

          各設計模式關鍵詞

          看完了上述設計模式后,把它們的關鍵詞特點羅列出來,以后提到某種設計模式,進而聯想相應的關鍵詞和例子,從而心中有數。

          工廠模式

          工廠模式定義一個用于創建對象的接口,這個接口由子類決定實例化哪一個類。該模式使一個類的實例化延遲到了子類。而子類可以重寫接口方法以便創建的時候指定自己的對象類型。

          class Product {
              constructor(name) {
                  this.name = name
              }
              init() {
                  console.log('init')
              }
              fun() {
                  console.log('fun')
              }
          }
          
          class Factory {
              create(name) {
                  return new Product(name)
              }
          }
          
          // use
          let factory = new Factory()
          let p = factory.create('p1')
          p.init()
          p.fun()
          

          適用場景

          • 如果你不想讓某個子系統與較大的那個對象之間形成強耦合,而是想運行時從許多子系統中進行挑選的話,那么工廠模式是一個理想的選擇
          • 將new操作簡單封裝,遇到new的時候就應該考慮是否用工廠模式;
          • 需要依賴具體環境創建不同實例,這些實例都有相同的行為,這時候我們可以使用工廠模式,簡化實現的過程,同時也可以減少每種對象所需的代碼量,有利于消除對象間的耦合,提供更大的靈活性

          優點

          • 創建對象的過程可能很復雜,但我們只需要關心創建結果。
          • 構造函數和創建者分離, 符合“開閉原則”
          • 一個調用者想創建一個對象,只要知道其名稱就可以了。
          • 擴展性高,如果想增加一個產品,只要擴展一個工廠類就可以。

          缺點

          • 添加新產品時,需要編寫新的具體產品類,一定程度上增加了系統的復雜度
          • 考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度

          什么時候不用

          當被應用到錯誤的問題類型上時,這一模式會給應用程序引入大量不必要的復雜性.除非為創建對象提供一個接口是我們編寫的庫或者框架的一個設計上目標,否則我會建議使用明確的構造器,以避免不必要的開銷。

          由于對象的創建過程被高效的抽象在一個接口后面的事實,這也會給依賴于這個過程可能會有多復雜的單元測試帶來問題。

          例子

          • 曾經我們熟悉的JQuery的$()就是一個工廠函數,它根據傳入參數的不同創建元素或者去尋找上下文中的元素,創建成相應的jQuery對象
          class jQuery {
              constructor(selector) {
                  super(selector)
              }
              add() {
                  
              }
            // 此處省略若干API
          }
          
          window.$ = function(selector) {
              return new jQuery(selector)
          }
          
          • vue 的異步組件

          在大型應用中,我們可能需要將應用分割成小一些的代碼塊,并且只在需要的時候才從服務器加載一個模塊。為了簡化,Vue 允許你以一個工廠函數的方式定義你的組件,這個工廠函數會異步解析你的組件定義。Vue 只有在這個組件需要被渲染的時候才會觸發該工廠函數,且會把結果緩存起來供未來重渲染。例如:

          Vue.component('async-example', function (resolve, reject) {
            setTimeout(function () {
              // 向 `resolve` 回調傳遞組件定義
              resolve({
                template: '<div>I am async!</div>'
              })
            }, 1000)
          })
          

          單例模式

          一個類只有一個實例,并提供一個訪問它的全局訪問點。

           class LoginForm {
              constructor() {
                  this.state = 'hide'
              }
              show() {
                  if (this.state === 'show') {
                      alert('已經顯示')
                      return
                  }
                  this.state = 'show'
                  console.log('登錄框顯示成功')
              }
              hide() {
                  if (this.state === 'hide') {
                      alert('已經隱藏')
                      return
                  }
                  this.state = 'hide'
                  console.log('登錄框隱藏成功')
              }
           }
           LoginForm.getInstance = (function () {
               let instance
               return function () {
                  if (!instance) {
                      instance = new LoginForm()
                  }
                  return instance
               }
           })()
          
          let obj1 = LoginForm.getInstance()
          obj1.show()
          
          let obj2 = LoginForm.getInstance()
          obj2.hide()
          
          console.log(obj1 === obj2)
          

          優點

          • 劃分命名空間,減少全局變量
          • 增強模塊性,把自己的代碼組織在一個全局變量名下,放在單一位置,便于維護
          • 且只會實例化一次。簡化了代碼的調試和維護

          缺點

          • 由于單例模式提供的是一種單點訪問,所以它有可能導致模塊間的強耦合 從而不利于單元測試。無法單獨測試一個調用了來自單例的方法的類,而只能把它與那個單例作為一個單元一起測試。

          場景例子

          • 定義命名空間和實現分支型方法
          • 登錄框
          • vuex 和 redux中的store

          適配器模式

          將一個類的接口轉化為另外一個接口,以滿足用戶需求,使類之間接口不兼容問題通過適配器得以解決。

          class Plug {
            getName() {
              return 'iphone充電頭';
            }
          }
          
          class Target {
            constructor() {
              this.plug = new Plug();
            }
            getName() {
              return this.plug.getName() + ' 適配器Type-c充電頭';
            }
          }
          
          let target = new Target();
          target.getName(); // iphone充電頭 適配器轉Type-c充電頭
          

          優點

          • 可以讓任何兩個沒有關聯的類一起運行。
          • 提高了類的復用。
          • 適配對象,適配庫,適配數據

          缺點

          • 額外對象的創建,非直接調用,存在一定的開銷(且不像代理模式在某些功能點上可實現性能優化)
          • 如果沒必要使用適配器模式的話,可以考慮重構,如果使用的話,盡量把文檔完善

          場景

          • 整合第三方SDK
          • 封裝舊接口
          // 自己封裝的ajax, 使用方式如下
          ajax({
              url: '/getData',
              type: 'Post',
              dataType: 'json',
              data: {
                  test: 111
              }
          }).done(function() {})
          // 因為歷史原因,代碼中全都是:
          // $.ajax({....})
          
          // 做一層適配器
          var $ = {
              ajax: function (options) {
                  return ajax(options)
              }
          }
          
          • vue的computed
          <template>
              <div id="example">
                  <p>Original message: "{{ message }}"</p>  <!-- Hello -->
                  <p>Computed reversed message: "{{ reversedMessage }}"</p>  <!-- olleH -->
              </div>
          </template>
          <script type='text/javascript'>
              export default {
                  name: 'demo',
                  data() {
                      return {
                          message: 'Hello'
                      }
                  },
                  computed: {
                      reversedMessage: function() {
                          return this.message.split('').reverse().join('')
                      }
                  }
              }
          </script>

          原有data 中的數據不滿足當前的要求,通過計算屬性的規則來適配成我們需要的格式,對原有數據并沒有改變,只改變了原有數據的表現形式

          不同點

          適配器與代理模式相似

          • 適配器模式: 提供一個不同的接口(如不同版本的插頭)
          • 代理模式: 提供一模一樣的接口

          裝飾者模式

          • 動態地給某個對象添加一些額外的職責,,是一種實現繼承的替代方案
          • 在不改變原對象的基礎上,通過對其進行包裝擴展,使原有對象可以滿足用戶的更復雜需求,而不會影響從這個類中派生的其他對象
          class Cellphone {
              create() {
                  console.log('生成一個手機')
              }
          }
          class Decorator {
              constructor(cellphone) {
                  this.cellphone = cellphone
              }
              create() {
                  this.cellphone.create()
                  this.createShell(cellphone)
              }
              createShell() {
                  console.log('生成手機殼')
              }
          }
          // 測試代碼
          let cellphone = new Cellphone()
          cellphone.create()
          
          console.log('------------')
          let dec = new Decorator(cellphone)
          dec.create()
          

          場景例子

          • 比如現在有4 種型號的自行車,我們為每種自行車都定義了一個單

          獨的類。現在要給每種自行車都裝上前燈、尾 燈和鈴鐺這3 種配件。如果使用繼承的方式來給 每種自行車創建子類,則需要 4×3 = 12 個子類。 但是如果把前燈、尾燈、鈴鐺這些對象動態組 合到自行車上面,則只需要額外增加3 個類

          • ES7 Decorator 阮一峰
          • core-decorators

          優點

          • 裝飾類和被裝飾類都只關心自身的核心業務,實現了解耦。
          • 方便動態的擴展功能,且提供了比繼承更多的靈活性。

          缺點

          • 多層裝飾比較復雜。
          • 常常會引入許多小對象,看起來比較相似,實際功能大相徑庭,從而使得我們的應用程序架構變得復雜起來

          代理模式

          是為一個對象提供一個代用品或占位符,以便控制對它的訪問

          假設當A 在心情好的時候收到花,小明表白成功的幾率有

          60%,而當A 在心情差的時候收到花,小明表白的成功率無限趨近于0。 小明跟A 剛剛認識兩天,還無法辨別A 什么時候心情好。如果不合時宜地把花送給A,花 被直接扔掉的可能性很大,這束花可是小明吃了7 天泡面換來的。 但是A 的朋友B 卻很了解A,所以小明只管把花交給B,B 會監聽A 的心情變化,然后選 擇A 心情好的時候把花轉交給A,代碼如下:

          let Flower = function() {}
          let xiaoming = {
            sendFlower: function(target) {
              let flower = new Flower()
              target.receiveFlower(flower)
            }
          }
          let B = {
            receiveFlower: function(flower) {
              A.listenGoodMood(function() {
                A.receiveFlower(flower)
              })
            }
          }
          let A = {
            receiveFlower: function(flower) {
              console.log('收到花'+ flower)
            },
            listenGoodMood: function(fn) {
              setTimeout(function() {
                fn()
              }, 1000)
            }
          }
          xiaoming.sendFlower(B)
          

          場景

          • HTML元 素事件代理
          <ul id="ul">
            <li>1</li>
            <li>2</li>
            <li>3</li>
          </ul>
          <script>
            let ul = document.querySelector('#ul');
            ul.addEventListener('click', event => {
              console.log(event.target);
            });
          </script>
          • ES6 的 proxy 阮一峰Proxy
          • jQuery.proxy()方法

          優點

          • 代理模式能將代理對象與被調用對象分離,降低了系統的耦合度。代理模式在客戶端和目標對象之間起到一個中介作用,這樣可以起到保護目標對象的作用
          • 代理對象可以擴展目標對象的功能;通過修改代理對象就可以了,符合開閉原則;

          缺點

          處理請求速度可能有差別,非直接訪問存在開銷

          不同點

          裝飾者模式實現上和代理模式類似

          • 裝飾者模式: 擴展功能,原有功能不變且可直接使用
          • 代理模式: 顯示原有功能,但是經過限制之后的

          外觀模式

          為子系統的一組接口提供一個一致的界面,定義了一個高層接口,這個接口使子系統更加容易使用

          1. 兼容瀏覽器事件綁定
          let addMyEvent = function (el, ev, fn) {
              if (el.addEventListener) {
                  el.addEventListener(ev, fn, false)
              } else if (el.attachEvent) {
                  el.attachEvent('on' + ev, fn)
              } else {
                  el['on' + ev] = fn
              }
          }; 
          
          1. 封裝接口
          let myEvent = {
              // ...
              stop: e => {
                  e.stopPropagation();
                  e.preventDefault();
              }
          };
          

          場景

          • 設計初期,應該要有意識地將不同的兩個層分離,比如經典的三層結構,在數據訪問層和業務邏輯層、業務邏輯層和表示層之間建立外觀Facade
          • 在開發階段,子系統往往因為不斷的重構演化而變得越來越復雜,增加外觀Facade可以提供一個簡單的接口,減少他們之間的依賴。
          • 在維護一個遺留的大型系統時,可能這個系統已經很難維護了,這時候使用外觀Facade也是非常合適的,為系系統開發一個外觀Facade類,為設計粗糙和高度復雜的遺留代碼提供比較清晰的接口,讓新系統和Facade對象交互,Facade與遺留代碼交互所有的復雜工作。

          參考: 大話設計模式

          優點

          • 減少系統相互依賴。
          • 提高靈活性。
          • 提高了安全性

          缺點

          • 不符合開閉原則,如果要改東西很麻煩,繼承重寫都不合適。

          觀察者模式

          定義了一種一對多的關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象的狀態發生變化時就會通知所有的觀察者對象,使它們能夠自動更新自己,當一個對象的改變需要同時改變其它對象,并且它不知道具體有多少對象需要改變的時候,就應該考慮使用觀察者模式。

          • 發布 & 訂閱
          • 一對多
          // 主題 保存狀態,狀態變化之后觸發所有觀察者對象
          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: ${this.subject.getState()}`)
            }
          }
          
          // 測試
          let s = new Subject()
          let o1 = new Observer('o1', s)
          let o2 = new Observer('02', s)
          
          s.setState(12)
          

          場景

          • DOM事件
          document.body.addEventListener('click', function() {
              console.log('hello world!');
          });
          document.body.click()
          
          • vue 響應式

          優點

          • 支持簡單的廣播通信,自動通知所有已經訂閱過的對象
          • 目標對象與觀察者之間的抽象耦合關系能單獨擴展以及重用
          • 增加了靈活性
          • 觀察者模式所做的工作就是在解耦,讓耦合的雙方都依賴于抽象,而不是依賴于具體。從而使得各自的變化都不會影響到另一邊的變化。

          缺點

          過度使用會導致對象與對象之間的聯系弱化,會導致程序難以跟蹤維護和理解

          狀態模式

          允許一個對象在其內部狀態改變的時候改變它的行為,對象看起來似乎修改了它的類

          // 狀態 (弱光、強光、關燈)
          class State {
              constructor(state) {
                  this.state = state
              }
              handle(context) {
                  console.log(`this is ${this.state} light`)
                  context.setState(this)
              }
          }
          class Context {
              constructor() {
                  this.state = null
              }
              getState() {
                  return this.state
              }
              setState(state) {
                  this.state = state
              }
          }
          // test 
          let context = new Context()
          let weak = new State('weak')
          let strong = new State('strong')
          let off = new State('off')
          
          // 弱光
          weak.handle(context)
          console.log(context.getState())
          
          // 強光
          strong.handle(context)
          console.log(context.getState())
          
          // 關閉
          off.handle(context)
          console.log(context.getState())
          

          場景

          • 一個對象的行為取決于它的狀態,并且它必須在運行時刻根據狀態改變它的行為
          • 一個操作中含有大量的分支語句,而且這些分支語句依賴于該對象的狀態

          優點

          • 定義了狀態與行為之間的關系,封裝在一個類里,更直觀清晰,增改方便
          • 狀態與狀態間,行為與行為間彼此獨立互不干擾
          • 用對象代替字符串來記錄當前狀態,使得狀態的切換更加一目了然

          缺點

          • 會在系統中定義許多狀態類
          • 邏輯分散

          迭代器模式

          提供一種方法順序一個聚合對象中各個元素,而又不暴露該對象的內部表示。

          class Iterator {
              constructor(conatiner) {
                  this.list = conatiner.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)
              }
          }
          
          // 測試代碼
          let container = new Container([1, 2, 3, 4, 5])
          let iterator = container.getIterator()
          while(iterator.hasNext()) {
            console.log(iterator.next())
          }
          

          場景例子

          • Array.prototype.forEach
          • jQuery中的$.each()
          • ES6 Iterator

          特點

          • 訪問一個聚合對象的內容而無需暴露它的內部表示。
          • 為遍歷不同的集合結構提供一個統一的接口,從而支持同樣的算法在不同的集合結構上進行操作

          總結

          對于集合內部結果常常變化各異,不想暴露其內部結構的話,但又想讓客戶代碼透明的訪問其中的元素,可以使用迭代器模式

          橋接模式

          橋接模式(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()
          

          優點

          • 有助于獨立地管理各組成部分, 把抽象化與實現化解耦
          • 提高可擴充性

          缺點

          • 大量的類將導致開發成本的增加,同時在性能方面可能也會有所減少。

          組合模式

          • 將對象組合成樹形結構,以表示“整體-部分”的層次結構。
          • 通過對象的多態表現,使得用戶對單個對象和組合對象的使用具有一致性。
          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()
          

          場景

          • 表示對象-整體層次結構
          • 希望用戶忽略組合對象和單個對象的不同,用戶將統一地使用組合結構中的所有對象(方法)

          缺點

          如果通過組合模式創建了太多的對象,那么這些對象可能會讓系統負擔不起。

          原型模式

          原型模式(prototype)是指用原型實例指向創建對象的種類,并且通過拷貝這些原型創建新的對象。

          class Person {
            constructor(name) {
              this.name = name
            }
            getName() {
              return this.name
            }
          }
          class Student extends Person {
            constructor(name) {
              super(name)
            }
            sayHello() {
              console.log(`Hello, My name is ${this.name}`)
            }
          }
          
          let student = new Student("xiaoming")
          student.sayHello()
          

          原型模式,就是創建一個共享的原型,通過拷貝這個原型來創建新的類,用于創建重復的對象,帶來性能上的提升。

          策略模式

          定義一系列的算法,把它們一個個封裝起來,并且使它們可以互相替換

          <html>
          <head>
              <title>策略模式-校驗表單</title>
              <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
          </head>
          <body>
              <form id = "registerForm" method="post" action="http://xxxx.com/api/register">
                  用戶名:<input type="text" name="userName">
                  密碼:<input type="text" name="password">
                  手機號碼:<input type="text" name="phoneNumber">
                  <button type="submit">提交</button>
              </form>
              <script type="text/javascript">
                  // 策略對象
                  const strategies = {
                    isNoEmpty: function (value, errorMsg) {
                      if (value === '') {
                        return errorMsg;
                      }
                    },
                    isNoSpace: function (value, errorMsg) {
                      if (value.trim() === '') {
                        return errorMsg;
                      }
                    },
                    minLength: function (value, length, errorMsg) {
                      if (value.trim().length < length) {
                        return errorMsg;
                      }
                    },
                    maxLength: function (value, length, errorMsg) {
                      if (value.length > length) {
                        return errorMsg;
                      }
                    },
                    isMobile: function (value, errorMsg) {
                      if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(value)) {
                        return errorMsg;
                      }                
                    }
                  }
                  
                  // 驗證類
                  class Validator {
                    constructor() {
                      this.cache = []
                    }
                    add(dom, rules) {
                      for(let i = 0, rule; rule = rules[i++];) {
                        let strategyAry = rule.strategy.split(':')
                        let errorMsg = rule.errorMsg
                        this.cache.push(() => {
                          let strategy = strategyAry.shift()
                          strategyAry.unshift(dom.value)
                          strategyAry.push(errorMsg)
                          return strategies[strategy].apply(dom, strategyAry)
                        })
                      }
                    }
                    start() {
                      for(let i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
                        let errorMsg = validatorFunc()
                        if (errorMsg) {
                          return errorMsg
                        }
                      }
                    }
                  }
          
                  // 調用代碼
                  let registerForm = document.getElementById('registerForm')
          
                  let validataFunc = function() {
                    let validator = new Validator()
                    validator.add(registerForm.userName, [{
                      strategy: 'isNoEmpty',
                      errorMsg: '用戶名不可為空'
                    }, {
                      strategy: 'isNoSpace',
                      errorMsg: '不允許以空白字符命名'
                    }, {
                      strategy: 'minLength:2',
                      errorMsg: '用戶名長度不能小于2位'
                    }])
                    validator.add(registerForm.password, [ {
                      strategy: 'minLength:6',
                      errorMsg: '密碼長度不能小于6位'
                    }])
                    validator.add(registerForm.phoneNumber, [{
                      strategy: 'isMobile',
                      errorMsg: '請輸入正確的手機號碼格式'
                    }])
                    return validator.start()
                  }
          
                  registerForm.onsubmit = function() {
                    let errorMsg = validataFunc()
                    if (errorMsg) {
                      alert(errorMsg)
                      return false
                    }
                  }
              </script>
          </body>
          </html>

          場景例子

          • 如果在一個系統里面有許多類,它們之間的區別僅在于它們的'行為',那么使用策略模式可以動態地讓一個對象在許多行為中選擇一種行為。
          • 一個系統需要動態地在幾種算法中選擇一種。
          • 表單驗證

          優點

          • 利用組合、委托、多態等技術和思想,可以有效的避免多重條件選擇語句
          • 提供了對開放-封閉原則的完美支持,將算法封裝在獨立的strategy中,使得它們易于切換,理解,易于擴展
          • 利用組合和委托來讓Context擁有執行算法的能力,這也是繼承的一種更輕便的代替方案

          缺點

          • 會在程序中增加許多策略類或者策略對象
          • 要使用策略模式,必須了解所有的strategy,必須了解各個strategy之間的不同點,這樣才能選擇一個合適的strategy

          享元模式

          運用共享技術有效地支持大量細粒度對象的復用。系統只使用少量的對象,而這些對象都很相似,狀態變化很小,可以實現對象的多次復用。由于享元模式要求能夠共享的對象必須是細粒度對象,因此它又稱為輕量級模式,它是一種對象結構型模式

          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個考生來考試
          

          場景例子

          • 文件上傳需要創建多個文件實例的時候
          • 如果一個應用程序使用了大量的對象,而這些大量的對象造成了很大的存儲開銷時就應該考慮使用享元模式

          優點

          • 大大減少對象的創建,降低系統的內存,使效率提高。

          缺點

          • 提高了系統的復雜度,需要分離出外部狀態和內部狀態,而且外部狀態具有固有化的性質,

          不應該隨著內部狀態的變化而變化,否則會造成系統的混亂

          模板方法模式

          模板方法模式由兩部分結構組成,第一部分是抽象父類,第二部分是具體的實現子類。通常在抽象父類中封裝了子類的算法框架,包括實現一些公共方法和封裝子類中所有方法的執行順序。子類通過繼承這個抽象類,也繼承了整個算法結構,并且可以選擇重寫父類的方法。

          class Beverage {
              constructor({brewDrink, addCondiment}) {
                  this.brewDrink = brewDrink
                  this.addCondiment = addCondiment
              }
              /* 燒開水,共用方法 */
              boilWater() { console.log('水已經煮沸=== 共用') }
              /* 倒杯子里,共用方法 */
              pourCup() { console.log('倒進杯子里===共用') }
              /* 模板方法 */
              init() {
                  this.boilWater()
                  this.brewDrink()
                  this.pourCup()
                  this.addCondiment()
              }
          }
          /* 咖啡 */
          const coffee = new Beverage({
               /* 沖泡咖啡,覆蓋抽象方法 */
               brewDrink: function() { console.log('沖泡咖啡') },
               /* 加調味品,覆蓋抽象方法 */
               addCondiment: function() { console.log('加點奶和糖') }
          })
          coffee.init() 
          

          場景例子

          • 一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現
          • 子類中公共的行為應被提取出來并集中到一個公共父類中的避免代碼重復

          優點

          • 提取了公共代碼部分,易于維護

          缺點

          • 增加了系統復雜度,主要是增加了的抽象類和類間聯系

          職責鏈模式

          使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系,將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止

          // 請假審批,需要組長審批、經理審批、總監審批
          class Action {
              constructor(name) {
                  this.name = name
                  this.nextAction = null
              }
              setNextAction(action) {
                  this.nextAction = action
              }
              handle() {
                  console.log( `${this.name} 審批`)
                  if (this.nextAction != null) {
                      this.nextAction.handle()
                  }
              }
          }
          
          let a1 = new Action("組長")
          let a2 = new Action("經理")
          let a3 = new Action("總監")
          a1.setNextAction(a2)
          a2.setNextAction(a3)
          a1.handle()
          

          場景例子

          • JS 中的事件冒泡
          • 作用域鏈
          • 原型鏈

          優點

          • 降低耦合度。它將請求的發送者和接收者解耦。
          • 簡化了對象。使得對象不需要知道鏈的結構
          • 增強給對象指派職責的靈活性。通過改變鏈內的成員或者調動它們的次序,允許動態地新增或者刪除責任
          • 增加新的請求處理類很方便。

          缺點

          • 不能保證某個請求一定會被鏈中的節點處理,這種情況可以在鏈尾增加一個保底的接受者節點來處理這種即將離開鏈尾的請求。
          • 使程序中多了很多節點對象,可能再一次請求的過程中,大部分的節點并沒有起到實質性的作用。他們的作用僅僅是讓請求傳遞下去,從性能當面考慮,要避免過長的職責鏈到來的性能損耗。

          命令模式

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

          // 接收者類
          class Receiver {
              execute() {
                console.log('接收者執行請求')
              }
            }
            
          // 命令者
          class Command {  
              constructor(receiver) {
                  this.receiver = receiver
              }
              execute () {    
                  console.log('命令');
                  this.receiver.execute()
              }
          }
          // 觸發者
          class Invoker {   
              constructor(command) {
                  this.command = command
              }
              invoke() {   
                  console.log('開始')
                  this.command.execute()
              }
          }
            
          // 倉庫
          const warehouse = new Receiver();   
          // 訂單    
          const order = new Command(warehouse);  
          // 客戶
          const client = new Invoker(order);      
          client.invoke()
          

          優點

          • 對命令進行封裝,使命令易于擴展和修改
          • 命令發出者和接受者解耦,使發出者不需要知道命令的具體執行過程即可執行

          缺點

          • 使用命令模式可能會導致某些系統有過多的具體命令類。

          備忘錄模式

          在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到保存的狀態。

          //備忘類
          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()) //444
          editor.getContentFromMemento(careTaker.get(1))
          console.log(editor.getContent()) //333
          
          editor.getContentFromMemento(careTaker.get(0))
          console.log(editor.getContent()) //222
          

          場景例子

          • 分頁控件
          • 撤銷組件

          優點

          • 給用戶提供了一種可以恢復狀態的機制,可以使用戶能夠比較方便地回到某個歷史的狀態

          缺點

          • 消耗資源。如果類的成員變量過多,勢必會占用比較大的資源,而且每一次保存都會消耗一定的內存。

          中介者模式

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

          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 * 10)
              }
              setB() {
                  let number = this.a.number
                  this.b.setNumber(number / 10)
              }
          }
          
          let a = new A()
          let b = new B()
          let m = new Mediator(a, b)
          a.setNumber(10, m)
          console.log(a.number, b.number)
          b.setNumber(10, m)
          console.log(a.number, b.number)
          

          場景例子

          • 系統中對象之間存在比較復雜的引用關系,導致它們之間的依賴關系結構混亂而且難以復用該對象
          • 想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。

          優點

          • 使各對象之間耦合松散,而且可以獨立地改變它們之間的交互
          • 中介者和對象一對多的關系取代了對象之間的網狀多對多的關系
          • 如果對象之間的復雜耦合度導致維護很困難,而且耦合度隨項目變化增速很快,就需要中介者重構代碼

          缺點

          • 系統中會新增一個中介者對象,因 為對象之間交互的復雜性,轉移成了中介者對象的復雜性,使得中介者對象經常是巨大的。中介 者對象自身往往就是一個難以維護的對象。

          解釋器模式

          給定一個語言, 定義它的文法的一種表示,并定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子。

          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);
          

          優點

          • 易于改變和擴展文法。
          • 由于在解釋器模式中使用類來表示語言的文法規則,因此可以通過繼承等機制來改變或擴展文法

          缺點

          • 執行效率較低,在解釋器模式中使用了大量的循環和遞歸調用,因此在解釋較為復雜的句子時其速度慢
          • 對于復雜的文法比較難維護

          訪問者模式

          表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。

          // 訪問者  
          class Visitor {
              constructor() {}
              visitConcreteElement(ConcreteElement) {
                  ConcreteElement.operation()
              }
          }
          // 元素類  
          class ConcreteElement{
              constructor() {
              }
              operation() {
                 console.log("ConcreteElement.operation invoked");  
              }
              accept(visitor) {
                  visitor.visitConcreteElement(this)
              }
          }
          // client
          let visitor = new Visitor()
          let element = new ConcreteElement()
          element.accept(visitor)
          

          場景例子

          • 對象結構中對象對應的類很少改變,但經常需要在此對象結構上定義新的操作
          • 需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而需要避免讓這些操作"污染"這些對象的類,也不希望在增加新操作時修改這些類。

          優點

          • 符合單一職責原則
          • 優秀的擴展性
          • 靈活性

          缺點

          • 具體元素對訪問者公布細節,違反了迪米特原則
          • 違反了依賴倒置原則,依賴了具體類,沒有依賴抽象。
          • 具體元素變更比較困難

          主站蜘蛛池模板: 一区二区三区视频网站| 中文字幕乱码一区二区免费| 无码精品人妻一区二区三区漫画| 国产午夜精品一区二区三区极品| 一区二区三区四区在线播放| 欧美日本精品一区二区三区| 3d动漫精品一区视频在线观看| 国产成人无码AV一区二区| 精品女同一区二区三区在线| 日韩一区二区三区射精| 91精品一区二区综合在线| 无码人妻久久一区二区三区免费 | 寂寞一区在线观看| 国产伦精品一区二区三区四区| 一区二区三区视频| 国产微拍精品一区二区| 怡红院美国分院一区二区| 99国产精品欧美一区二区三区| 亚洲一区二区三区高清在线观看 | 久久精品亚洲一区二区三区浴池 | 国产91久久精品一区二区| 亚洲国产老鸭窝一区二区三区| 熟妇人妻一区二区三区四区| 中文字幕色AV一区二区三区| 国产免费一区二区视频| 亚洲AV无码一区二区二三区入口| 亚洲色精品aⅴ一区区三区| 国产成人无码一区二区三区| 日韩精品一区二区三区中文| 精品黑人一区二区三区| 亲子乱av一区区三区40岁| 精品国产高清自在线一区二区三区 | 国产乱码精品一区二区三区四川| 手机福利视频一区二区| 免费一区二区无码视频在线播放| 视频在线一区二区| 日本成人一区二区三区| 亚洲色偷偷偷网站色偷一区| 国产在线精品一区二区在线看| 日本在线观看一区二区三区| 国产成人无码一区二区三区在线|