成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用 jsinspect 檢測前端代碼庫中的重復/近似代碼

開發 開發工具
在開發的過程中我們往往會存在大量的復制粘貼代碼的行為,這一點在項目的開發初期尤其顯著;而在項目逐步穩定,功能需求逐步完善之后我們就需要考慮對代碼庫的優化與重構,盡量編寫清晰可維護的代碼。

[[187087]]

在開發的過程中我們往往會存在大量的復制粘貼代碼的行為,這一點在項目的開發初期尤其顯著;而在項目逐步穩定,功能需求逐步完善之后我們就需要考慮對代碼庫的優化與重構,盡量編寫清晰可維護的代碼。好的代碼往往是在合理范圍內盡可能地避免重復代碼,遵循單一職責與 Single Source of Truth 等原則,本部分我們嘗試使用 jsinspect 對于代碼庫進行自動檢索,根據其反饋的重復或者近似的代碼片進行合理的優化。當然,我們并不是單純地追求公共代碼地完全剝離化,過度的抽象反而會降低代碼的可讀性與可理解性。jsinspect 利用 babylon 對于 JavaScript 或者 JSX 代碼構建 AST 語法樹,根據不同的 AST 節點類型,譬如 BlockStatement、VariableDeclaration、ObjectExpression 等標記相似結構的代碼塊。我們可以使用 npm 全局安裝 jsinspect 命令:

  1. Usage: jsinspect [options] <paths ...> 
  2.  
  3.  
  4. Detect copy-pasted and structurally similar JavaScript code 
  5. Example use: jsinspect -I -L -t 20 --ignore "test" ./path/to/src 
  6.  
  7.  
  8. Options: 
  9.  
  10.   -h, --help                         output usage information 
  11.   -V, --version                      output the version number 
  12.   -t, --threshold <number>           number of nodes (default: 30) 
  13.   -m, --min-instances <number>       min instances for a match (default: 2) 
  14.   -c, --config                       path to config file (default: .jsinspectrc) 
  15.   -r, --reporter [default|json|pmd]  specify the reporter to use 
  16.   -I, --no-identifiers               do not match identifiers 
  17.   -L, --no-literals                  do not match literals 
  18.   -C, --no-color                     disable colors 
  19.   --ignore <pattern>                 ignore paths matching a regex 
  20.   --truncate <number>                length to truncate lines (default: 100, off: 0) 

我們也可以選擇在項目目錄下添加 .jsinspect 配置文件指明 jsinspect 運行配置:

  1.   "threshold":     30, 
  2.   "identifiers":   true
  3.   "literals":      true
  4.   "ignore":        "test|spec|mock"
  5.   "reporter":      "json"
  6.   "truncate":      100, 

在配置完畢之后,我們可以使用 jsinspect -t 50 --ignore "test" ./path/to/src 來對于代碼庫進行分析,以筆者找到的某個代碼庫為例,其檢測出了上百個重復的代碼片,其中典型的代表如下所示。可以看到在某個組件中重復編寫了多次密碼輸入的元素,我們可以選擇將其封裝為函數式組件,將 label、hintText 等通用屬性包裹在內,從而減少代碼的重復率。

  1. Match - 2 instances 
  2.  
  3. ./src/view/main/component/tabs/account/operation/login/forget_password.js:96,110 
  4. return <div className="my_register__register"
  5.     <div className="item"
  6.         <Paper zDepth={2}> 
  7.             <EnhancedTextFieldWithLabel 
  8.                 label="密碼" 
  9.                 hintText="請輸入密碼,6-20位字母,數字" 
  10.                 onChange={(event, value)=> { 
  11.                     this.setState({ 
  12.                         userPwd: value 
  13.                     }) 
  14.                 }} 
  15.             /> 
  16.         </Paper> 
  17.     </div> 
  18.     <div className="item"
  19.  
  20. ./src/view/main/component/tabs/my/login/forget_password.js:111,125 
  21. return <div className="my_register__register"
  22.     <div className="item"
  23.         <Paper zDepth={2}> 
  24.             <EnhancedTextFieldWithLabel 
  25.                 label="密碼" 
  26.                 hintText="請輸入密碼,6-20位字母,數字" 
  27.                 onChange={(event, value)=> { 
  28.                     this.setState({ 
  29.                         userPwd: value 
  30.                     }) 
  31.                 }} 
  32.             /> 
  33.         </Paper> 
  34.     </div> 
  35.     <div className="item"

筆者也對于 React 源碼進行了簡要分析,在 246 個文件中共發現 16 個近似代碼片,并且其中的大部分重復源于目前基于 Stack 的調和算法與基于 Fiber 重構的調和算法之間的過渡時期帶來的重復,譬如:

  1. Match - 2 instances 
  2.  
  3. ./src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js:134,153 
  4.   var value = props.value; 
  5.   if (value != null) { 
  6.     // Cast `value` to a string to ensure the value is set correctly. While 
  7.     // browsers typically do this as necessary, jsdom doesn't. 
  8.     var newValue = '' + value; 
  9.  
  10.     // To avoid side effects (such as losing text selection), only set value if changed 
  11.     if (newValue !== node.value) { 
  12.       node.value = newValue; 
  13.     } 
  14.     if (props.defaultValue == null) { 
  15.       node.defaultValue = newValue; 
  16.     } 
  17.   } 
  18.   if (props.defaultValue != null) { 
  19.     node.defaultValue = props.defaultValue; 
  20.   } 
  21. }, 
  22.  
  23. postMountWrapper: function(element: Element, props: Object) { 
  24.  
  25. ./src/renderers/dom/stack/client/wrappers/ReactDOMTextarea.js:129,148 
  26.   var value = props.value; 
  27.   if (value != null) { 
  28.     // Cast `value` to a string to ensure the value is set correctly. While 
  29.     // browsers typically do this as necessary, jsdom doesn't. 
  30.     var newValue = '' + value; 
  31.  
  32.     // To avoid side effects (such as losing text selection), only set value if changed 
  33.     if (newValue !== node.value) { 
  34.       node.value = newValue; 
  35.     } 
  36.     if (props.defaultValue == null) { 
  37.       node.defaultValue = newValue; 
  38.     } 
  39.   } 
  40.   if (props.defaultValue != null) { 
  41.     node.defaultValue = props.defaultValue; 
  42.   } 
  43. }, 
  44.  
  45. postMountWrapper: function(inst) { 

筆者認為在新特性的開發過程中我們不一定需要時刻地考慮代碼重構,而是應該相對獨立地開發新功能。***我們再簡單地討論下 jsinspect 的工作原理,這樣我們可以在項目需要時自定義類似的工具以進行特殊代碼的匹配或者提取。jsinspect 的核心工作流可以反映在 inspector.js 文件中:

  1. ...  
  2. this._filePaths.forEach((filePath) => { 
  3.   var src = fs.readFileSync(filePath, {encoding: 'utf8'}); 
  4.   this._fileContents[filePath] = src.split('\n'); 
  5.   var syntaxTree = parse(src, filePath); 
  6.   this._traversals[filePath] = nodeUtils.getDFSTraversal(syntaxTree); 
  7.   this._walk(syntaxTree, (nodes) => this._insert(nodes)); 
  8. }); 
  9.  
  10. this._analyze(); 
  11. ... 

上述流程還是較為清晰的,jsinspect 會遍歷所有的有效源碼文件,提取其源碼內容然后通過 babylon 轉化為 AST 語法樹,某個文件的語法樹格式如下:

  1. Node { 
  2.   type: 'Program'
  3.   start: 0, 
  4.   end: 31, 
  5.   loc: 
  6.    SourceLocation { 
  7.      start: Position { line: 1, column: 0 }, 
  8.      end: Position { line: 2, column: 15 }, 
  9.      filename: './__test__/a.js' }, 
  10.   sourceType: 'script'
  11.   body: 
  12.    [ Node { 
  13.        type: 'ExpressionStatement'
  14.        start: 0, 
  15.        end: 15, 
  16.        loc: [Object], 
  17.        expression: [Object] }, 
  18.      Node { 
  19.        type: 'ExpressionStatement'
  20.        start: 16, 
  21.        end: 31, 
  22.        loc: [Object], 
  23.        expression: [Object] } ], 
  24.   directives: [] } 
  25. './__test__/a.js': [ 'console.log(a);''console.log(b);' ] } 

其后我們通過深度優先遍歷算法在 AST 語法樹上構建所有節點的數組,然后遍歷整個數組構建待比較對象。這里我們在運行時輸入的 -t 參數就是用來指定分割的原子比較對象的維度,當我們將該參數指定為 2 時,經過遍歷構建階段形成的內部映射數組 _map 結構如下:

  1. 'uj3VAExwF***vx0SGBDFu8beU+Lk=': [ [ [Object], [Object] ], [ [Object], [Object] ] ], 
  2.   'eMqg1hUXEFYNbKkbsd2QWECLiYU=': [ [ [Object], [Object] ], [ [Object], [Object] ] ], 
  3.   'gvSCaZfmhte6tfnpfmnTeH+eylw=': [ [ [Object], [Object] ], [ [Object], [Object] ] ], 
  4.   'eHqT9EuPomhWLlo9nwU0DWOkcXk=': [ [ [Object], [Object] ], [ [Object], [Object] ] ] } 

如果有大規模代碼數據的話我們可能形成很多有重疊的實例,這里使用了 _omitOverlappingInstances 函數來進行去重;譬如如果某個實例包含節點 abcd,另一個實例包含節點組 bcde,那么會選擇將后者從數組中移除。另一個優化加速的方法就是在每次比較結束之后移除已經匹配到的代碼片:

  1. _prune(nodeArrays) { 
  2.   for (let i = 0; i < nodeArrays.length; i++) { 
  3.     let nodes = nodeArrays[i]; 
  4.     for (let j = 0; j < nodes.length; j++) { 
  5.       this._removeNode(nodes[j]); 
  6.     } 
  7.   } 
  8. }

【本文是51CTO專欄作者“張梓雄 ”的原創文章,如需轉載請通過51CTO與作者聯系】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2009-07-22 07:45:00

Scala代碼重復

2009-07-15 18:07:47

JDBC代碼

2022-09-23 14:44:31

前端huskyeslint

2022-04-07 10:02:58

前端檢測工具

2021-08-08 08:08:20

木馬無文件Cobalt Stri

2021-04-22 15:08:01

代碼評審郵件

2022-08-01 23:45:23

代碼識別項目

2014-01-08 09:33:57

重復IP地址IP檢測

2021-09-03 08:21:20

前端代碼模塊

2023-12-04 07:06:11

2016-10-19 20:34:46

2025-02-17 07:00:00

ORB對象跟蹤器計算機視覺

2023-09-26 08:29:27

2023-11-23 13:07:18

代碼Golang

2022-08-28 10:08:53

前端代碼前端

2023-05-31 08:00:00

PromptrGPT人工智能

2011-08-24 12:49:56

SQL Server托管代碼

2021-02-26 10:45:49

PyCaret低代碼Python

2020-04-26 10:01:14

編程學習技術

2011-05-05 09:54:05

靜態代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 羞羞色影院 | 欧美精品在线观看 | 人人九九精 | 亚洲午夜视频 | 激情五月婷婷丁香 | 久久久国产一区 | 亚洲精品一二三区 | 91夜色在线观看 | 国产精品99久久久久久久vr | 国产精品一区二区在线观看 | 亚洲福利片 | 亚洲一区视频在线 | 久久久久久国产精品免费免费 | 91视频在线| 岛国毛片在线观看 | 亚洲精品视频在线看 | 精品日韩 | 日日操夜夜操天天操 | 欧美黄色性生活视频 | 亚洲精品在线看 | 日本精品一区 | 亚洲福利在线观看 | 草草视频在线观看 | 精品久久久久久久久久久久久久 | 国产a级毛毛片 | 超碰欧美| 欧美一区二区在线观看视频 | 激情视频中文字幕 | 亚洲精品日韩综合观看成人91 | a级免费观看视频 | 99久久精品免费看国产高清 | 国产一级片在线播放 | 伊人网国产| 日本大香伊一区二区三区 | 国产精品久久久久久久久久久久久久 | 毛片久久久 | 亚洲一区二区精品视频 | 久久久久久九九九九 | 日本天天色 | 日韩欧美视频 | 免费在线观看成人 |