日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

編寫(xiě)可維護(hù)的 JavaScript 代碼 -- 編程風(fēng)格,編程實(shí)踐 讀書(shū)筆記

 路人甲Java 2020-02-11

編程風(fēng)格

基本格式化

  • 4空格縮進(jìn)
  • 不省略分號(hào)(在原生及使用工具函數(shù)的情況不建議省略,在使用比較完善的框架如vue或者自己配置好 webpack 時(shí)可以省略)
  • 1行代碼長(zhǎng)度不超過(guò)80個(gè)字符(個(gè)人比較推薦,畢竟編輯器的自動(dòng)換行有時(shí)真的很難受)
  • 運(yùn)算符后換行,換行后增加2個(gè)縮進(jìn)單位(變量賦值換行,變量保持和上一行等號(hào)右側(cè)第一個(gè)變量對(duì)齊)
  • 空行,流控制語(yǔ)句之前,方法之間,變量和第一條語(yǔ)句之間,注釋之前,
  • 變量和函數(shù)命名方式,小駝峰方式
  • 變量命名名詞開(kāi)頭,函數(shù)命名動(dòng)詞開(kāi)頭,命名長(zhǎng)度盡可能短,盡量體現(xiàn)出值得數(shù)據(jù)類型

    • can 函數(shù)返回布爾值
    • has 函數(shù)返回布爾值
    • is 函數(shù)返回布爾值
    • get 函數(shù)返回非布爾值
    • set 函數(shù)用來(lái)保存值
  • 常量使用大寫(xiě)字母和下劃線來(lái)命名,下劃線分割單詞 (URL MAX_NUMBER)
  • 構(gòu)造函數(shù)(class) 大駝峰命名方式
  • 字符串,統(tǒng)一用單引號(hào),多行字符或者需要攜帶參數(shù)使用反引號(hào)
  • 數(shù)字,不要省略浮點(diǎn)數(shù)小數(shù)點(diǎn)前后的部分
  • null 當(dāng)做對(duì)象占位符
  • 避免使用 undefined
  • 創(chuàng)建對(duì)象時(shí)使用對(duì)象直接量: {}
  • 創(chuàng)建數(shù)組時(shí)使用數(shù)組直接量: []

注釋

  • 單行注釋

    • 獨(dú)占一行,注釋前總是有一個(gè)空行,縮進(jìn)與下一行代碼保持一致
    • 代碼行尾部,代碼結(jié)束到注釋之間有一個(gè)空格,代碼加上注釋不應(yīng)超過(guò)單行最大字符數(shù)限制,超過(guò)了就應(yīng)放到當(dāng)前代碼行的上方
    • 單行注釋不應(yīng)以連續(xù)多行注釋的形式出現(xiàn)
  • 多行注釋

    • 最少三行第一行 / , 第二行 與上一行 對(duì)齊,最后一行 / (單行多行注釋區(qū)分開(kāi)比較好,多行注釋風(fēng)格很多,這里只是一種,找到適合的就好)

      
      /*
       *空格 + 注釋
       */
    • 注釋前總是有一個(gè)空行,縮進(jìn)與下一行代碼保持一致
    • 代碼結(jié)束到注釋之間有一個(gè)縮進(jìn)
  • 添加注釋的一般原則

    • 需要讓代碼表達(dá)的意思更清晰
    • 難以理解的代碼
    • 可能被認(rèn)為錯(cuò)誤的代碼
    • 瀏覽器特性 hack
  • 文檔注釋

    • 最流行的 javaDoc 文檔格式
    • 多行注釋以單斜杠加雙星號(hào)開(kāi)頭 /**
    • 接下來(lái)是描述信息
    • 使用 @ 來(lái)表示一個(gè)或多個(gè)屬性
    /**
     *注釋
     *@ 變量1 {String} 一個(gè)字符串變量
     */    
  • 如何添加文檔注釋

    • 所有的方法: 方法作用,期望的參數(shù),返回值 進(jìn)行描述
    • 所有的構(gòu)造函數(shù)(類): 自定義類型,期望的參數(shù)添加描述
    • 所有包含文檔化方法的對(duì)象: 如果對(duì)象包含一個(gè)或多個(gè)附帶文檔注釋的方法,那么這個(gè)對(duì)象也應(yīng)適當(dāng)添加文檔注釋
    • 文檔生成工具 (jsdoc:目前還在維護(hù)更新,使用量,star數(shù)也比較多)
    • 注:使用文檔生成工具要使用工具要求的注釋風(fēng)格

語(yǔ)句和表達(dá)式

  • 塊語(yǔ)句都應(yīng)使用花括號(hào)

    • if...else...
    • switch
    • for
    • while
    • do..while..
    • try...catch...
    • ...
  • 花括號(hào)對(duì)齊方式,左花括號(hào)擋在塊語(yǔ)句的第一行末尾

    if () {
        
    } else {
        
    }
  • 塊語(yǔ)句間隔

    • 語(yǔ)句名,小括號(hào),花括號(hào)都沒(méi)有空格

      if(true){
          
      }
    • 小括號(hào)左右加空格

      if (true) {
          
      }
    • 小括號(hào)左右加空格,小括號(hào)與小括號(hào)內(nèi)容之間加空格

      if ( true ) {
          
      }
  • switch 語(yǔ)句

    • 縮進(jìn)

      • 每條 case 語(yǔ)句相對(duì)于 switch 關(guān)鍵字縮進(jìn)一個(gè)層級(jí),每條 case 語(yǔ)句后都有一個(gè)空行

        switch (color) {
          case '#000':
              break
          
          case '#f00':
              break
          
          case '#00F':
              break
          
          default:
              break
        }
      • case 和 switch 左對(duì)齊,且沒(méi)有空行

          switch (color) {
          case '#000':
              break
          case '#00F':
              break
          default:
              break
        }
    • 連續(xù)執(zhí)行: 有意連續(xù)執(zhí)行需要加注釋,其他情況默認(rèn)每條語(yǔ)句結(jié)束必須是 break,return,throw
    • default:如果default什么也沒(méi)做,加上注釋,省略default
  • while 語(yǔ)句 盡量避免使用,因?yàn)樵趪?yán)格模式下不能運(yùn)行,而且容易造成對(duì)于變量的認(rèn)知錯(cuò)誤

    let message = '你好!'
    let book = {
      name: '少少',
      age: 18,
      message: '你好嗎?'
    }
    
    with (book) {
        message += name
        console.log(message)
    }
  • for 循環(huán) 遍歷數(shù)組

    • break 立即退出循環(huán)
    • commit 跳過(guò)本次循環(huán) // 盡量避免這種方式
  • for-in 循環(huán) 遍歷對(duì)象

    • 不用定義任何控制條件,返回屬性名而不是值
    • 不僅遍歷對(duì)象的實(shí)例屬性同樣遍歷從原型繼承來(lái)的屬性,往往因意外的結(jié)果而終止

      • 使用 hasOwnProperty() 過(guò)濾實(shí)例屬性,除非想查找原型鏈

變量 函數(shù) 運(yùn)算符

  • 變量聲明

    • 集中在函數(shù)頂部
    • 在有相關(guān)性時(shí),合并變量聲明

      let value = 10,
          result = 10,
          i,
          len;
  • 函數(shù)聲明

    • 先聲明后使用
    • 函數(shù)聲明不應(yīng)該出現(xiàn)在語(yǔ)句塊之內(nèi)
  • 函數(shù)調(diào)用間隔

    • 函數(shù)名和小括號(hào)之間沒(méi)有空格
  • 立即調(diào)用的函數(shù)

    const myFunction = function () {
        // 函數(shù)
    }
    let value = function () {
        return 'string' // 變量
    }()
    
    // 好的寫(xiě)法
    let value = (function () {
        return 'string'  
    }())
  • 嚴(yán)格模式 "use strict"

    • 盡可能使用嚴(yán)格模式
    • 不在全局使用嚴(yán)格模式

      function () {
          "use strict"
          
      }
      
      (function () {
          "use strict"
          function () {
              
          }
          function () {
              
          }
          function () {
              
          }
      })()
  • 相等 JavaScript 有強(qiáng)制類型轉(zhuǎn)換機(jī)制

    • 數(shù)字 與 字符串比較,嘗試將字符串轉(zhuǎn)換數(shù)字
    • 數(shù)字 與 布爾值比較,嘗試將布爾值轉(zhuǎn)換為數(shù)字
    • 對(duì)象 與 其他類型,先調(diào)用valueOf(),沒(méi)有就調(diào)用toString()
    • 使用 === 和 !==

編程實(shí)踐

UI 層的松耦合

  • 什么是松耦合:修改一個(gè)組件而不需要修改其他的組件;組件知道的越少,越有利于形成整個(gè)系統(tǒng)
  • 將 js 代碼和 css 代碼分離開(kāi),需要操作樣式時(shí)最佳方法是操作 className,除非需要 js 計(jì)算 css 的屬性(比如常見(jiàn)的輪播圖)
  • 將 html 和 js 代碼分離開(kāi)

    • 從服務(wù)器加載
    • 客戶端模板(Handlebars)

避免使用全局變量

  • 全局變量帶來(lái)的問(wèn)題

    • 命名沖突
    • 代碼脆弱性,依賴全局變量,任何地方都能改變?nèi)肿兞康闹?/li>
    • 難以測(cè)試依賴全局變量的函數(shù)
  • 意外的全局變量

    • 當(dāng)使用一個(gè)未被聲明的變量時(shí),JavaScript會(huì)自動(dòng)創(chuàng)建為全局變量
  • 單全局變量

    • 創(chuàng)建的這個(gè)唯一全局對(duì)象名是獨(dú)一無(wú)二的(不會(huì)和內(nèi)置API產(chǎn)生沖突),并將所有的功能代碼全都掛載到這個(gè)全局對(duì)象上,因此每個(gè)可能的全局變量都會(huì)成為你唯一的全局對(duì)象的屬性,從而不會(huì)創(chuàng)建多個(gè)全局變量

      
      // 再比如表示三本書(shū)
      // 方法一
      function Book (name) {
          return `書(shū)名:${name}`
      }
      const Book1 = Book("name1")
      const Book2 = Book("name2")
      const Book3 = Book("name3")
      
      console.log(Book1, Book2, Book3)
      
      // 單全局變量
      class Books {
          Book1 = Book("name1")
          Book2 = Book("name2")
          Book3 = Book("name3")
          
          Book (name) {
              return `書(shū)名:${name}`
          }
      }
      
      console.log(Books.Book1, Books.Book2, Books.Book3)
      
      /*
       *其他例子: jQuery 定義了 $ 和 jQuery
       *以及vue 定義了 Vue
       */
    • 命名空間(在類中定義分組,方便管理)

      class My {
          dom = {
              addDom () {
                  ...
              },
              removeDom () {
                  ...
              }
              ...
          }
          
          event = {
              onClick () {
                  ...
              },
              oninput () {
                ...  
              }
              ...
          }
      }

事件處理

  • 典型用法 (流水賬式寫(xiě)法)

    
    // 常見(jiàn)但是不推薦的寫(xiě)法 
    handleClick (event) {
        const popup = document.getElementById("popup")
        popup.style.left = event.clientX
        popup.style.top = event.clientY
        popup.className = "show"
    }
  • 隔離應(yīng)用邏輯 應(yīng)用邏輯和用戶行為應(yīng)該區(qū)分開(kāi)(一個(gè)函數(shù)只做一件事,便于函數(shù)復(fù)用)

    clas Myapp {
        handleClick (event) {
          this.showPopup(event)  
        },
        showPopup (event) {
          const popup = document.getElementById("popup")
          popup.style.left = event.clientX
          popup.style.top = event.clientY
          popup.className = "show"
        }
    }
  • 不要分發(fā)事件對(duì)象 應(yīng)用邏輯不應(yīng)該依賴 event 對(duì)象來(lái)完成功能(便于測(cè)試,便于函數(shù)復(fù)用)

     clas Myapp {
        handleClick (event) {
        
          // 事件處理程序是接觸 event 對(duì)象的唯一函數(shù) (一個(gè)函數(shù)只做一件事)
          event.preventDefault()
          event.stopPropagation()
          
          // 傳入應(yīng)用邏輯
          this.showPopup(event.clientX, event.clientY)  
        },
        showPopup (x, y) {
          const popup = document.getElementById("popup")
          popup.style.left = x
          popup.style.top = y
          popup.className = "show"
        }
    }

避免空比較

  • 使用 "typeof 變量" 的方式檢測(cè) 字符串,數(shù)字,布爾值,undefined,函數(shù),
  • 使用 "變量 instanceof 對(duì)象" 的方式檢測(cè)某個(gè)值的引用類型(不能用于檢測(cè)是否屬于 Object,因?yàn)?js 所有的值原型鏈最終都是 Object )
  • 檢測(cè)數(shù)組 (es5已有自帶檢測(cè)方法)

    
    // 關(guān)注對(duì)象能做什么,而不是他是什么
    function isArr(value) {
        return typeof value.sort === 'function'
    }
    
    // 更為優(yōu)雅有效的解決方案 (兼容 IE6 以下版本)
    function isArray (value) {
        if (typeof Array.isArray === 'function') {
            return Array.isArray(value) // 自帶判斷數(shù)組方法
        } else {
        
            // 某個(gè)值內(nèi)置的 toString 在所有的瀏覽器中都會(huì)返回標(biāo)準(zhǔn)的字符串結(jié)果
            return Object.prototype.toString.call(value) === '[object Array]'
        }
    }
  • 檢測(cè)屬性是否存在

    • 不好的寫(xiě)法,通過(guò)給定的名字檢查屬性的值

      let myObject = {
          count: 0
      }
      
      if (myObject['count']) {
          // 存在但不執(zhí)行
      }
    • 好的寫(xiě)法,通過(guò) in 運(yùn)算符或者 hasOwnPrperty()

      let myObject = {
          count: 0
      }
      
      if ('count' in myObject) { // in 只檢查屬性是否存在于對(duì)象實(shí)例或者對(duì)象原型
          // 執(zhí)行
      }
      
      if (myObject.hasOwnPrperty('count')) { // 只檢查是否存在于對(duì)象實(shí)例
          // 執(zhí)行
      }

將配置數(shù)據(jù)從代碼中分離出來(lái)

  • 什么是配置數(shù)據(jù) 寫(xiě)死在代碼里,且將來(lái)可能會(huì)被修改

    • 接口地址
    • 重復(fù)的值
    • 設(shè)置(比如頁(yè)面配置項(xiàng))
    • 任何可能發(fā)生變更的值
    • ...
  • 抽離配置數(shù)據(jù),把配置數(shù)據(jù)拿到外部(類似 vue 中的 data)
  • 保存配置文件,把配置單獨(dú)保存到文件(類似 vue-cli 搭建的項(xiàng)目中 vue.config.js 的作用)

拋出自定義錯(cuò)誤

  • 什么是錯(cuò)誤 幫助我們快速定位代碼 bug ,以便于調(diào)試維護(hù)
  • JavaScript 拋出錯(cuò)誤的方法

    throw new Error('錯(cuò)誤信息')
  • 如何書(shū)寫(xiě)拋出的錯(cuò)誤文本

    throw new Error('函數(shù)名: 可能的原因')
  • 什么時(shí)候拋出錯(cuò)誤

    • 不確定自己的函數(shù)在哪些地方調(diào)用
    • 工具函數(shù)
    • JavaScript 類庫(kù) (函數(shù)調(diào)用棧應(yīng)該在進(jìn)入庫(kù)代碼接口的時(shí)候就終止;意思是在調(diào)用類庫(kù)時(shí)先要校驗(yàn)然后進(jìn)行相應(yīng)的提示,而不是等到)
    • 修復(fù)了一個(gè)很難調(diào)試的錯(cuò)誤,這時(shí)添加一兩個(gè)自定義錯(cuò)誤
    • 不想要某種情況發(fā)生,為避免這種情況
  • try-catch 語(yǔ)句 catch 代碼塊不能省略或留空

    能在錯(cuò)誤拋出前解析它;
    拋出錯(cuò)誤會(huì)中斷 js 進(jìn)程, 使用 try-catch 則不會(huì)中斷 js 進(jìn)程
    
    個(gè)人理解: try-catch 語(yǔ)句可以用在自己知道可能會(huì)出錯(cuò)但是不能明確的知道錯(cuò)誤原因,
    或者在報(bào)錯(cuò)后仍需繼續(xù)報(bào)錯(cuò)代碼塊之后語(yǔ)句的情況下

不是自己的對(duì)象不要?jiǎng)?/h2>
  • 什么是自己的對(duì)象

    • 自己創(chuàng)建了一個(gè)對(duì)象,那么自己擁有這個(gè)對(duì)象
    • 自己不是創(chuàng)建對(duì)象的人,但是負(fù)責(zé)維護(hù)代碼,那么也擁有這個(gè)對(duì)象
    • 只是使用者,不要修改對(duì)象
  • 對(duì)象的使用原則

    • 不覆蓋對(duì)象原型上的屬性,方法
    • 不在對(duì)象原型新增屬性,方法
    • 不刪除對(duì)象原型上的屬性,方法
    • 如何使用?

      • 繼承
      • 設(shè)計(jì)模式之外觀模式(門(mén)面模式 Facade Pattern)
  • 防止對(duì)象被修改

    • Object.preventExtensions(對(duì)象名) 該方法不能向?qū)ο笾行绿砑訉傩院头椒?,但是可以修改?duì)象中存在的屬性
    • Object.seal(對(duì)象名) 密封對(duì)象不能新添加屬性、不能刪除屬性。
    • Object.freeze(對(duì)象名) 凍結(jié)對(duì)象,即是不可擴(kuò)展的,也是密封的,而且其屬性值也不能修改

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多