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

          【JS】1150- 如何寫出更優(yōu)雅的 JavaScript 代碼

          共 4931字,需瀏覽 10分鐘

           ·

          2021-11-27 12:46

          有人說(shuō)好的代碼像一首詩(shī),優(yōu)雅而有內(nèi)涵。

          在日常開發(fā)中,維護(hù)別人老代碼的時(shí)候是不是總感覺(jué)邏輯混亂,無(wú)法入手,就跟屎山一樣?改一個(gè) BUG 就如同在這座屎山上面艱難地再拉一坨……今天,我們從日常開發(fā)的角度上面談?wù)勅绾巫屪约旱拇a更清晰,更易于維護(hù),讓別人看起來(lái)更有逼格。

          變量命名

          要寫出好代碼,變量命名至關(guān)重要。我們盡量采用富有表現(xiàn)力的詞,英文不好多用翻譯軟件,保證不出現(xiàn)錯(cuò)誤單詞。編輯器可以安裝相關(guān)的拼寫檢查、翻譯插件。

          1. 不要縮寫/簡(jiǎn)寫單詞,除非這些單詞已經(jīng)公認(rèn)可以被這樣縮寫/簡(jiǎn)寫。這樣做導(dǎo)致可讀性下降,意義表達(dá)不明確。反例:Association assStringBuilder sb
          2. 普通變量命名則使用名詞及名詞短語(yǔ)。比如 valueoptionsfileTextcolumnName
          3. boolean 命名,如果表示“是不是”用 is...,表示“有沒(méi)有”用 has...,表示“能不能”用 can...,表示“能不能怎么樣”用 ...able
          4. function 命名采用動(dòng)詞/賓語(yǔ)順序。比如 getUserInfoinsertRowsclearValue
          5. 避免使用 _ 開頭、tempmy 之類命名臨時(shí)變量,臨時(shí)變量也是有意義的,這些都會(huì)增加閱讀代碼時(shí)的噪點(diǎn)
          6. 避免無(wú)意義的命名,你起的每一個(gè)名字都要能表明意思。比如 userInfoclickCount 反例 infocount

          代碼結(jié)構(gòu)

          好的代碼結(jié)構(gòu)有助于我們保持理性的思路,降低心智負(fù)擔(dān)。

          使用 const 定義

          如果沒(méi)有復(fù)雜的邏輯,用 const 就足夠了,這樣不用擔(dān)心變量被重新賦值而引起意外情況。當(dāng)這種模式寫多之后,你會(huì)發(fā)現(xiàn)在項(xiàng)目中幾乎找不到幾個(gè)用 let 的地方。

          //?Bad
          let?result?=?false;
          if?(userInfo.age?>?30)?{
          ??result?=?true;
          }

          //?Good
          const?result?=?userInfo.age?>?30;

          邏輯歸類

          在復(fù)雜的邏輯中,相關(guān)的邏輯盡量放在一起,并插入空行分開。使代碼結(jié)構(gòu)看起來(lái)清晰明了。

          提前返回

          function 中經(jīng)常會(huì)遇到變量值為 undefined 的情況,這個(gè)時(shí)候則需要提前判斷并阻止執(zhí)行,避免一些不必要的分支(無(wú) else),讓代碼更精煉。

          if?(!userInfo)?{
          ??return;
          }

          if?(!hasMoney)?{
          ??return;
          }

          //?執(zhí)行業(yè)務(wù)邏輯

          優(yōu)雅的條件判斷

          簡(jiǎn)單的判斷 if + return 就提前返回了。復(fù)雜邏輯 if else if 面條式代碼不夠優(yōu)雅,想用 switch case?實(shí)際情況看來(lái) if elseswitch case 用法區(qū)別不大。

          //?if?else
          if?(status?==?1)?{
          ??console.log('processing');
          }?else?if?(status?==?2)?{
          ??console.log('fail');
          }?else?if?(status?==?3)?{
          ??console.log('success');
          }?else?if?(status?==?4)?{
          ??console.log('cancel');
          }?else?{
          ??console.log('other');
          }

          //?switch?case
          switch?(status)?{
          ??case?1:
          ????console.log('processing');
          ????break;
          ??case?2:
          ????console.log('fail');
          ????break;
          ??case?3:
          ????console.log('success');
          ????break;
          ??case?4:
          ????console.log('cancel');
          ????break;
          ??default:
          ????console.log('other');
          ????break;
          }

          在上面代碼中可以看出 switch caseif else 代碼行數(shù)還多,break 關(guān)鍵字也是必不可少,還不忘寫 default。這里我們推薦用 ObjectMap 作為條件存儲(chǔ)。

          const?actions?=?{
          ??1:?'processing',
          ??2:?'fail',
          ??3:?'success',
          ??4:?'cancel',
          ??default:?'other',
          };

          console.log(actions[status]????actions.default);

          Map 則更為強(qiáng)大,對(duì)象的鍵只能是一個(gè)字符串或符號(hào),但 Map 的鍵可以是對(duì)象或更多,可以作為條件聯(lián)合判斷。

          const?actions?=?new?Map([
          ??[/^sign_[1-3]$/,?()?=>?'A'],
          ??[/^sign_5$/,?()?=>?'B'],
          ??//...
          ]);

          const?action?=?[...actions].filter(([key,?value])?=>?key.test(`sign_${status}`));
          action.forEach(([key,?value])?=>?value());

          善用表達(dá)式

          善用表達(dá)式,避免面條式代碼。簡(jiǎn)單的條件判斷可以用三元運(yùn)算符代替。普通的 for 循環(huán)可以用 mapforEach 代替。

          降低復(fù)雜度

          一個(gè)邏輯的代碼行數(shù)越多,維護(hù)起來(lái)越困難,這個(gè)時(shí)候我們就需要將相關(guān)的邏輯抽離到另一個(gè) function 中,從而降低上下文的復(fù)雜度。這里我們建議是一個(gè) function 的代碼量在 120 個(gè)字符的寬度下不超過(guò)一個(gè)屏幕。

          值得注意的是, function 所定義的形參最好控制在 3 個(gè)以內(nèi),否則容易疏忽傳入的順序,從而變得不易維護(hù)。如果參數(shù)太多就需要將相關(guān)的參數(shù)聚合成對(duì)象傳遞。

          移除重復(fù)代碼

          重復(fù)代碼在 Bad Smell 中排在第一位,所以,竭盡你的全力去避免重復(fù)代碼。因?yàn)樗馕吨?dāng)你需要修改一些邏輯時(shí)會(huì)有多個(gè)地方需要修改。

          引入順序

          import 中,我們約定將 node_modules 中的包放在前面,然后是相對(duì)路徑的包。有時(shí)一個(gè) cssimport 順序不同就會(huì)導(dǎo)致執(zhí)行的優(yōu)先級(jí)不同。

          使用聲明式

          聲明式編程:告訴“機(jī)器”你想要的是什么(what),讓機(jī)器想出如何去做(how)。命令式編程:命令“機(jī)器”如何去做事情(how),這樣不管你想要的是什么(what),它都會(huì)按照你的命令實(shí)現(xiàn)。世界很美妙,遠(yuǎn)離命令式,節(jié)省時(shí)間體驗(yàn)生活。

          //?聲明式:篩選我需要的結(jié)果
          const?result?=?dataSource.filter((dataItem)?=>?dataItem.age?>?10);

          //?命令式:親力而為查找/追加數(shù)據(jù)
          let?result?=?[];
          dataSource.forEach((dataItem)?=>?{
          ??if?(dataItem.age?>?10)?{
          ????result.push(dataItem);
          ??}
          });

          這個(gè)時(shí)候有人就會(huì)說(shuō)命令式編程性能好。其實(shí)我們寫代碼無(wú)需做過(guò)早優(yōu)化,那點(diǎn)性能損耗與可維護(hù)性比起來(lái)可以算是九牛一毛。

          寫好業(yè)務(wù)注釋

          優(yōu)秀的代碼命名無(wú)需注釋,代碼即注釋,加上注釋就會(huì)冗余。這時(shí)某個(gè)業(yè)務(wù)的邏輯就離不開準(zhǔn)確的注釋,這樣可以幫助我們更加理解業(yè)務(wù)的詳細(xì)邏輯。需要要求的是代碼改動(dòng)注釋也要隨之更新。

          函數(shù)式編程

          函數(shù)式編程獲得越來(lái)越多的關(guān)注,包括 react 都遵循這個(gè)理念。

          函數(shù)是"第一等公民"

          變量可以一個(gè)函數(shù),可以作為另一個(gè)函數(shù)的參數(shù)

          function?increaseOperator(user)?{
          ??return?user.age?+?1;
          }

          userList.filter(Boolean).map(increaseOperator);

          純函數(shù)

          即相同輸入,永遠(yuǎn)會(huì)得到相同輸出,而且沒(méi)有任何可觀察的副作用。如果使用了 setTimeoutPromise 或更多具有意外情況發(fā)生的操作。那么這類操作被稱之為 "副作用" Effect

          每一個(gè)函數(shù)都可以被看做獨(dú)立單元。純函數(shù)的好處:方便組合、可緩存、可測(cè)試、引用透明、易于并發(fā)等等。

          //?不純的,?minimum?可能被其他操作改變
          let?minimum?=?21;

          function?checkAge(age)?{
          ??return?age?>=?minimum;
          }

          //?純的
          function?checkAge(age)?{
          ??const?minimum?=?21;
          ??return?age?>=?minimum;
          }

          比如 slicespliceslice 符合純函數(shù)的定義是因?yàn)閷?duì)相同輸入它保證能返回相同輸出。而 splice 卻會(huì)改變調(diào)用它的數(shù)組,這就會(huì)產(chǎn)生可觀察到的副作用,即這個(gè)原始數(shù)組永久地改變了。

          var?countList?=?[1,?2,?3,?4,?5];

          //?純的
          countList.slice(0,?3);
          //=>?[1,?2,?3]

          countList.slice(0,?3);
          //=>?[1,?2,?3]

          //?不純的
          countList.splice(0,?3);
          //=>?[1,?2,?3]

          countList.splice(0,?3);
          //=>?[4,?5]

          不可變數(shù)據(jù)

          每次操作不修改原先的值,而是返回一個(gè)新的值,這與無(wú)副作用相呼應(yīng)。不可變數(shù)據(jù)模型易于調(diào)試,不用擔(dān)心當(dāng)前數(shù)據(jù)被別的地方更改。

          //?Bad?修改了參數(shù)
          function?updateUser(user)?{
          ??user.age?=?10;
          }

          //?Good?返回新的對(duì)象
          function?updateUser(user)?{
          ??return?{
          ????...user,
          ????age:?10,
          ??};
          }

          這里推薦 immer 作為函數(shù)式不可變數(shù)據(jù)操作。

          完善的 TS 類型

          typescript 擁有強(qiáng)大的類型系統(tǒng),彌補(bǔ)了 javascript 在類型上的短板。我們?cè)趯?typescript 代碼的時(shí)候需要注意的是,不使用隱式/顯示的 any 類型,若有不確定類型的情況,首先考慮的是 泛型 去約束它,其次則用 unknown 加斷言,最后才是 any

          //?典型類型完備的函數(shù)
          function?pick<T,?K?extends?keyof?T>(obj:?T,?keys:?K[])?{
          ??return?Object.fromEntries(keys.map((key)?=>?[key,?obj[key]]))?as?Pick;
          }

          pick(userInfo,?['email',?'name']);

          結(jié)合 prettier + eslint

          在團(tuán)隊(duì)協(xié)作中,統(tǒng)一的代碼尤為重要,目前社區(qū)中的 eslint 規(guī)則層出不窮。其中 eslint-config-airbnb 限制最為嚴(yán)格,很多開源團(tuán)隊(duì)都在用。這里我們可以與 prettier 搭配用,并禁用其中互相沖突的規(guī)則。編碼指南 https://github.com/airbnb/javascript

          結(jié)語(yǔ)

          想寫出優(yōu)雅的代碼其實(shí)很簡(jiǎn)單,千里之行,始于足下。我們需要不斷優(yōu)化自己的代碼,不要畏懼改善代碼質(zhì)量所需付出的努力。理解這些準(zhǔn)則并實(shí)踐,假以時(shí)日,相信我們每個(gè)人寫代碼都能做到像寫詩(shī)一樣行云流水。

          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計(jì)模式 重溫系列(9篇全)
          4.?正則 / 框架 / 算法等 重溫系列(16篇全)
          5.?Webpack4 入門(上)||?Webpack4 入門(下)
          6.?MobX 入門(上)?||??MobX 入門(下)
          7. 120+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

          點(diǎn)擊“閱讀原文”查看 130+ 篇原創(chuàng)文章

          瀏覽 28
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  国产青青操逼视频 | 鸡巴操美女 | 亚洲无码高清视频在线观看 | 尤物视频黄 | 97人妻少妇 |