<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【JavaScript】編寫高質(zhì)量JavaScript模塊的4個(gè)最佳實(shí)踐

          共 4542字,需瀏覽 10分鐘

           ·

          2021-05-13 21:13

          在網(wǎng)上看到一篇不錯(cuò)的文章, 里面的最佳實(shí)踐筆者已經(jīng)在實(shí)際項(xiàng)目中實(shí)踐了很久. 確實(shí)香~分享給大家. 

          譯文地址[1]

          這篇文章提供了關(guān)于如何更好地組織 JavaScript 模塊的 4 個(gè)最佳實(shí)踐。

          盡可能使用 named exports

          最開始使用 JavaScript 模塊時(shí),使用 export default 來導(dǎo)出模塊定義的單個(gè)塊,不管是類還是函數(shù)。例如:

          // greeter.js
          export default class Greeter {
          constructor(name) {
          this.name = name;
          }

          greet() {
          return `Hello, ${this.name}!`;
          }
          }

          import x from './greeter.js'

          隨著時(shí)間的推移,特別是在進(jìn)行大規(guī)模重構(gòu)的時(shí)候, 很難根據(jù) Greeter 去找到相關(guān)的引用.可維護(hù)性大大降低.
          更糟糕的是,編輯器沒有提供建議, 我們需要自己寫導(dǎo)入的類名.

          于是, 我們轉(zhuǎn)向了 named exports。讓我們來看看它的好處:

          // greeter.js
          export class Greeter {
          constructor(name) {
          this.name = name;
          }

          greet() {
          return `Hello, ${this.name}!`;
          }
          }
          import {Greeter} from './greeter.js'

          通過使用 named exports,編輯器可以更好地重命名:每次更改原始類名時(shí),所有使用者模塊都會(huì)自動(dòng)更改類名。

          而且編輯器還會(huì)提供建議, 不再盲打代碼, 如下:

          因此, 建議使用 named exports,以便在重命名重構(gòu)和代碼自動(dòng)完成中獲益。

          注意: 使用 React,Lodash 等第三方模塊時(shí), default import 通常是可以的。因?yàn)樗麄儗?dǎo)入名稱是一個(gè)不變的常量:React,_。

          惰性 import 對象

          模塊級范圍不應(yīng)該進(jìn)行繁重的計(jì)算,比如解析 JSON、發(fā)出 HTTP 請求、讀取本地存儲(chǔ)等等。

          例如,下面的模塊配置解析來自全局變量 bigJsonString 的配置

          // configuration.js
          export const configuration = {
          // Bad
          data: JSON.parse(bigJsonString)
          };

          這是一個(gè)問題,因?yàn)?bigJsonString 的解析是在模塊級范圍內(nèi)完成的。導(dǎo)入配置模塊時(shí),實(shí)際上將進(jìn)行 bigJsonString 的解析:

          // Bad: parsing happens when the module is imported
          import { configuration } from 'configuration';

          export function AboutUs() {
          return <p>{configuration.data.siteName}</p>;
          }

          在更高的級別上,模塊級 scope 的角色是定義模塊組件、導(dǎo)入依賴項(xiàng)和導(dǎo)出公共組件:這是依賴項(xiàng)解析過程。它應(yīng)該與運(yùn)行時(shí)分離:解析 JSON、發(fā)出請求、處理事件。

          讓我們重構(gòu)配置模塊來執(zhí)行延遲解析

          // configuration.js
          let parsedData = null;

          export const configuration = {
          // Good
          get data() {
          if (parsedData === null) {
          parsedData = JSON.parse(bigJsonString);
          }
          return parsedData;
          }
          };

          因?yàn)?data 屬性被定義為一個(gè) getter,所以只有在使用者訪問 configuration.data 時(shí)才會(huì)解析 bigJsonString。

          // Good: JSON parsing doesn't happen when the module is imported
          import { configuration } from 'configuration';

          export function AboutUs() {
          // JSON parsing happens now
          return <p>{configuration.data.companyDescription}</p>;
          }

          消費(fèi)者更清楚什么時(shí)候進(jìn)行大的操作。使用者可能決定在瀏覽器空閑時(shí)執(zhí)行該操作。或者,使用者可能會(huì)導(dǎo)入模塊,但是出于某種原因,不使用它。這為更深入的性能優(yōu)化提供了機(jī)會(huì):減少交互時(shí)間,最小化主線程工作。

          導(dǎo)入時(shí),模塊不應(yīng)執(zhí)行任何繁重的工作。相反,使用者應(yīng)該決定何時(shí)執(zhí)行運(yùn)行時(shí)操作。

          編寫高內(nèi)聚模塊

          內(nèi)聚性描述了模塊內(nèi)的組件屬于整體。高內(nèi)聚模塊的函數(shù)、類或變量是密切相關(guān)的。他們專注于一項(xiàng)任務(wù)。formatDate 模塊具有很高的內(nèi)聚性,因?yàn)樗墓δ苊芮邢嚓P(guān).

          // formatDate.js
          const MONTHS = [
          'January', 'February', 'March','April', 'May',
          'June', 'July', 'August', 'September', 'October',
          'November', 'December'
          ];

          function ensureDateInstance(date) {
          if (typeof date === 'string') {
          return new Date(date);
          }
          return date;
          }

          export function formatDate(date) {
          date = ensureDateInstance(date);
          const monthName = MONTHS[date.getMonth())];
          return `${monthName} ${date.getDate()}, ${date.getFullYear()}`;
          }

          formatDate()、ensureDateInstance()和 MONTHS 彼此密切相關(guān)。刪除 MONTHS 或 ensureDateInstance()會(huì)破壞 formatDate():這是高內(nèi)聚的標(biāo)志。

          低內(nèi)聚模塊的問題

          另一方面,低內(nèi)聚模塊。是指那些包含彼此不相關(guān)的組件。下面的 utils 模塊有 3 個(gè)執(zhí)行不同任務(wù)的函數(shù).

          // utils.js
          import cookies from 'cookies';

          export function getRandomInRange(start, end) {
          return start + Math.floor((end - start) * Math.random());
          }

          export function pluralize(itemName, count) {
          return count > 1 ? `${itemName}s` : itemName;
          }

          export function cookieExists(cookieName) {
          const cookiesObject = cookie.parse(document.cookie);
          return cookieName in cookiesObject;
          }

          getRandomInRange(), pluralize() and cookieExists() 刪除任一個(gè)函數(shù), 都不會(huì)影響整個(gè)模塊的功能.

          低內(nèi)聚模塊迫使使用者依賴于它并不需要的模塊,這就創(chuàng)建了不需要的傳遞依賴。

          例如,組件 ShoppingCartCount 從 utils 模塊導(dǎo)入 pluralize()函數(shù)

          // ShoppingCartCount.jsx
          import { pluralize } from 'utils';

          export function ShoppingCartCount({ count }) {
          return (
          <div>
          Shopping cart has {count} {pluralize('product', count)}
          </div>

          );
          }

          雖然 ShoppingCartCount 模塊只使用 utils 模塊之外的 pluralize() 函數(shù),但它對 cookie 模塊具有傳遞依賴關(guān)系(cookie 模塊導(dǎo)入到 utils 中)。

          好的解決方案是將低內(nèi)聚性模塊 utils 分成幾個(gè)高內(nèi)聚性模塊:utils / random,utils / stringFormat 和 utils / cookies。

          現(xiàn)在,如果 ShoppingCard 模塊導(dǎo)入 utils / stringFormat,那么它就不會(huì)對 Cookie 產(chǎn)生傳遞依賴:

          // ShoppingCartCount.jsx
          import { pluralize } from 'utils/stringFormat';

          export function ShoppingCartCount({ count }) {
          // ...
          }

          高內(nèi)聚模塊的最佳示例是 Node 內(nèi)置模塊,例如 fs,path,assert。

          推薦編寫功能、類和變量緊密相關(guān)的高內(nèi)聚模塊。你可以通過將大的低內(nèi)聚模塊重構(gòu)為多個(gè)高內(nèi)聚模塊。

          避免長的相對路徑

          對于下面的代碼, 我們很難知道它的父級組件, 而且一旦文件發(fā)生變化, 也得一遍一遍地改寫路徑.

          import { compareDates } from '../../../date/compare';
          import { formatDate } from '../../../date/format';

          // Use compareDates and formatDate

          因此,我建議避免使用相對路徑,而使用絕對路徑:

          import { compareDates } from 'utils/date/compare';
          import { formatDate } from 'utils/date/format';

          雖然絕對路徑有時(shí)寫起來比較長,但是使用它們可以清楚地顯示導(dǎo)入模塊的位置。我們可以使用 babel-plugin-module-resolver 來方便地定義絕對路徑.

          使用絕對路徑而不是長的相對路徑。


          參考資料

          [1]

          譯文地址: https://dmitripavlutin.com/javascript-modules-best-practices/


          瀏覽 52
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产福利久久久 | 波多野结衣一品二品免费观看AV | 黄色干逼视频 | 国产原创AV成人网站 | 无码一区二区黑人猛烈视频网站 |