摘要:使用檢測前端代碼庫中的重復(fù)近似代碼從屬于筆者的前端入門與工程實踐,更多前端相關(guān)學(xué)習(xí)資料推薦閱讀前端每周清單第期學(xué)習(xí)資源,發(fā)布,六問程序員如何成長泛前端知識圖譜。利用對于或者代碼構(gòu)建語法樹,根據(jù)不同的節(jié)點類型,譬如等標記相似結(jié)構(gòu)的代碼塊。
使用 jsinspect 檢測前端代碼庫中的重復(fù)/近似代碼 從屬于筆者的 Web 前端入門與工程實踐,更多前端相關(guān)學(xué)習(xí)資料推薦閱讀前端每周清單第6期:Angular 4.0學(xué)習(xí)資源,Egg.js 1.0發(fā)布,六問CTO程序員如何成長、泛前端知識圖譜(Web/iOS/Android/RN)。
在開發(fā)的過程中我們往往會存在大量的復(fù)制粘貼代碼的行為,這一點在項目的開發(fā)初期尤其顯著;而在項目逐步穩(wěn)定,功能需求逐步完善之后我們就需要考慮對代碼庫的優(yōu)化與重構(gòu),盡量編寫清晰可維護的代碼。好的代碼往往是在合理范圍內(nèi)盡可能地避免重復(fù)代碼,遵循單一職責與 Single Source of Truth 等原則,本部分我們嘗試使用 jsinspect 對于代碼庫進行自動檢索,根據(jù)其反饋的重復(fù)或者近似的代碼片進行合理的優(yōu)化。當然,我們并不是單純地追求公共代碼地完全剝離化,過度的抽象反而會降低代碼的可讀性與可理解性。jsinspect 利用 babylon 對于 JavaScript 或者 JSX 代碼構(gòu)建 AST 語法樹,根據(jù)不同的 AST 節(jié)點類型,譬如 BlockStatement、VariableDeclaration、ObjectExpression 等標記相似結(jié)構(gòu)的代碼塊。我們可以使用 npm 全局安裝 jsinspect 命令:
Usage: jsinspect [options]Detect copy-pasted and structurally similar JavaScript code Example use: jsinspect -I -L -t 20 --ignore "test" ./path/to/src Options: -h, --help output usage information -V, --version output the version number -t, --threshold number of nodes (default: 30) -m, --min-instances min instances for a match (default: 2) -c, --config path to config file (default: .jsinspectrc) -r, --reporter [default|json|pmd] specify the reporter to use -I, --no-identifiers do not match identifiers -L, --no-literals do not match literals -C, --no-color disable colors --ignore ignore paths matching a regex --truncate length to truncate lines (default: 100, off: 0)
我們也可以選擇在項目目錄下添加 .jsinspect 配置文件指明 jsinspect 運行配置:
{ "threshold": 30, "identifiers": true, "literals": true, "ignore": "test|spec|mock", "reporter": "json", "truncate": 100, }
在配置完畢之后,我們可以使用 jsinspect -t 50 --ignore "test" ./path/to/src 來對于代碼庫進行分析,以筆者找到的某個代碼庫為例,其檢測出了上百個重復(fù)的代碼片,其中典型的代表如下所示。可以看到在某個組件中重復(fù)編寫了多次密碼輸入的元素,我們可以選擇將其封裝為函數(shù)式組件,將 label、hintText 等通用屬性包裹在內(nèi),從而減少代碼的重復(fù)率。
Match - 2 instances ./src/view/main/component/tabs/account/operation/login/forget_password.js:96,110 return{ this.setState({ userPwd: value }) }} /> ./src/view/main/component/tabs/my/login/forget_password.js:111,125 return{ this.setState({ userPwd: value }) }} /> 筆者也對于 React 源碼進行了簡要分析,在 246 個文件中共發(fā)現(xiàn) 16 個近似代碼片,并且其中的大部分重復(fù)源于目前基于 Stack 的調(diào)和算法與基于 Fiber 重構(gòu)的調(diào)和算法之間的過渡時期帶來的重復(fù),譬如:
Match - 2 instances ./src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js:134,153 var value = props.value; if (value != null) { // Cast `value` to a string to ensure the value is set correctly. While // browsers typically do this as necessary, jsdom doesn"t. var newValue = "" + value; // To avoid side effects (such as losing text selection), only set value if changed if (newValue !== node.value) { node.value = newValue; } if (props.defaultValue == null) { node.defaultValue = newValue; } } if (props.defaultValue != null) { node.defaultValue = props.defaultValue; } }, postMountWrapper: function(element: Element, props: Object) { ./src/renderers/dom/stack/client/wrappers/ReactDOMTextarea.js:129,148 var value = props.value; if (value != null) { // Cast `value` to a string to ensure the value is set correctly. While // browsers typically do this as necessary, jsdom doesn"t. var newValue = "" + value; // To avoid side effects (such as losing text selection), only set value if changed if (newValue !== node.value) { node.value = newValue; } if (props.defaultValue == null) { node.defaultValue = newValue; } } if (props.defaultValue != null) { node.defaultValue = props.defaultValue; } }, postMountWrapper: function(inst) {筆者認為在新特性的開發(fā)過程中我們不一定需要時刻地考慮代碼重構(gòu),而是應(yīng)該相對獨立地開發(fā)新功能。最后我們再簡單地討論下 jsinspect 的工作原理,這樣我們可以在項目需要時自定義類似的工具以進行特殊代碼的匹配或者提取。jsinspect 的核心工作流可以反映在 inspector.js 文件中:
... this._filePaths.forEach((filePath) => { var src = fs.readFileSync(filePath, {encoding: "utf8"}); this._fileContents[filePath] = src.split(" "); var syntaxTree = parse(src, filePath); this._traversals[filePath] = nodeUtils.getDFSTraversal(syntaxTree); this._walk(syntaxTree, (nodes) => this._insert(nodes)); }); this._analyze(); ...上述流程還是較為清晰的,jsinspect 會遍歷所有的有效源碼文件,提取其源碼內(nèi)容然后通過 babylon 轉(zhuǎn)化為 AST 語法樹,某個文件的語法樹格式如下:
Node { type: "Program", start: 0, end: 31, loc: SourceLocation { start: Position { line: 1, column: 0 }, end: Position { line: 2, column: 15 }, filename: "./__test__/a.js" }, sourceType: "script", body: [ Node { type: "ExpressionStatement", start: 0, end: 15, loc: [Object], expression: [Object] }, Node { type: "ExpressionStatement", start: 16, end: 31, loc: [Object], expression: [Object] } ], directives: [] } { "./__test__/a.js": [ "console.log(a);", "console.log(b);" ] }其后我們通過深度優(yōu)先遍歷算法在 AST 語法樹上構(gòu)建所有節(jié)點的數(shù)組,然后遍歷整個數(shù)組構(gòu)建待比較對象。這里我們在運行時輸入的 -t 參數(shù)就是用來指定分割的原子比較對象的維度,當我們將該參數(shù)指定為 2 時,經(jīng)過遍歷構(gòu)建階段形成的內(nèi)部映射數(shù)組 _map 結(jié)構(gòu)如下:
{ "uj3VAExwF5Avx0SGBDFu8beU+Lk=": [ [ [Object], [Object] ], [ [Object], [Object] ] ], "eMqg1hUXEFYNbKkbsd2QWECLiYU=": [ [ [Object], [Object] ], [ [Object], [Object] ] ], "gvSCaZfmhte6tfnpfmnTeH+eylw=": [ [ [Object], [Object] ], [ [Object], [Object] ] ], "eHqT9EuPomhWLlo9nwU0DWOkcXk=": [ [ [Object], [Object] ], [ [Object], [Object] ] ] }如果有大規(guī)模代碼數(shù)據(jù)的話我們可能形成很多有重疊的實例,這里使用了 _omitOverlappingInstances 函數(shù)來進行去重;譬如如果某個實例包含節(jié)點 abcd,另一個實例包含節(jié)點組 bcde,那么會選擇將后者從數(shù)組中移除。另一個優(yōu)化加速的方法就是在每次比較結(jié)束之后移除已經(jīng)匹配到的代碼片:
_prune(nodeArrays) { for (let i = 0; i < nodeArrays.length; i++) { let nodes = nodeArrays[i]; for (let j = 0; j < nodes.length; j++) { this._removeNode(nodes[j]); } } }文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/82229.html
相關(guān)文章
JavaScript權(quán)威指南筆記(上)-語言核心
摘要:二進制浮點數(shù)和四舍五入錯誤在使用實數(shù)時,常常只是真實值的一個近似表示。作用域分類全局函數(shù),塊級作用域鏈變量對象用于存儲執(zhí)行上下文中的變量函數(shù)聲明函數(shù)參數(shù)變量初始化階段瀏覽器截圖瀏覽器截圖代碼執(zhí)行階段類和模塊 詞法結(jié)構(gòu) 字符集 使用Unicode編寫 ES3 Unicode2.1+ ES5 Unicode3+ 區(qū)分大小寫 注釋 // 注釋 /* 注釋 */ 標識符和保留字 必須以字...
咋做長文本去重
摘要:新問題拋出有沒有一種簽名算法,如果文本非常相似,簽名值也非常相似呢二文本相似性的簽名算法上文提出的問題,可以用局部敏感哈希解決,局部敏感哈希是一類文本越相似,哈希值越相似的算法,有興趣的同學(xué)自行百度,這里分享一下的思路。 緣起:(1)原創(chuàng)不易,互聯(lián)網(wǎng)抄襲成風(fēng),很多原創(chuàng)內(nèi)容在網(wǎng)上被抄來抄去,改來改去(2)百度的網(wǎng)頁庫非常大,爬蟲如何判斷一個新網(wǎng)頁是否與網(wǎng)頁庫中已有的網(wǎng)頁重復(fù)呢?這是本文要...
算法分析 - Algorithms, Part I, week 1 ANALYSIS OF ALGO
摘要:實際上這個情形中存在冪定律實際上絕大多數(shù)的計算機算法的運行時間滿足冪定律。基于研究得知,原則上我們能夠獲得算法,程序或者操作的性能的精確數(shù)學(xué)模型。 前言 上一篇:并查集下一篇:棧和隊列 在算法性能上我們常常面臨的挑戰(zhàn)是我們的程序能否求解實際中的大型輸入:--為什么程序運行的慢?--為什么程序耗盡了內(nèi)存? 沒有理解算法的性能特征會導(dǎo)致客戶端的性能很差,為了避免這種情況的出線,需要具備算法...
JavaScript 工作原理之三-內(nèi)存管理及如何處理 4 類常見的內(nèi)存泄漏問題(譯)
摘要:這是因為我們訪問了數(shù)組中不存在的數(shù)組元素它超過了最后一個實際分配到內(nèi)存的數(shù)組元素字節(jié),并且有可能會讀取或者覆寫的位。包含個元素的新數(shù)組由和數(shù)組元素所組成中的內(nèi)存使用中使用分配的內(nèi)存主要指的是內(nèi)存讀寫。 原文請查閱這里,本文有進行刪減,文后增了些經(jīng)驗總結(jié)。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第三章。 我們將會討論日常使用中另一個被開發(fā)...
發(fā)表評論
0條評論
ZoomQuiet
男|高級講師
TA的文章
閱讀更多
#黑五#DediPath:VPS和混合服務(wù)器永久3.5折,獨立服務(wù)器$39/月起
閱讀 1319·2021-11-24 10:24
基于Vue3最新標準,實現(xiàn)后臺前端綜合解決方案MK
閱讀 4162·2021-11-22 15:29
Issues with position fixed & scroll(移動端 fixed
閱讀 1091·2019-08-30 15:53
原生CSS+JS實現(xiàn)連續(xù)點擊旋轉(zhuǎn)
閱讀 2798·2019-08-30 10:54
一小波DOM騷操作:querySelectorAll和classList
閱讀 1986·2019-08-29 17:26
步步向前之Element-UI
閱讀 1290·2019-08-29 17:08
詳解 CSS 屬性 - 優(yōu)先級問題
閱讀 610·2019-08-28 17:55
Jenkins與Rainbond對接部署應(yīng)用
閱讀 1586·2019-08-26 14:01