<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 代碼優(yōu)化之道

          共 19022字,需瀏覽 39分鐘

           ·

          2022-09-17 11:24

          我們先引入一句話:

          代碼主要是為了寫給人看的,而不是寫給機器看的,只是順便也能用機器執(zhí)行而已。

          代碼和語言文字一樣是為了表達思想、記載信息,所以寫得清楚能更有效地表達。本文多數(shù)總結(jié)自《重構(gòu):改善既有代碼的設(shè)計(第2版)》我們直接進入正題,上代碼!

          提煉函數(shù)

          what

          將一段代碼提煉到一個獨立的函數(shù)中,并以這段代碼的作用命名。

          where

          如果需要花時間瀏覽一段代碼才能弄清楚它到底要干什么,那么這時候就應(yīng)該將其提煉到一個函數(shù)中,并根據(jù)它所做的事命名。以后再讀這段代碼時,一眼就能知道這個函數(shù)的用途。

          how

          // ==================重構(gòu)前==================
          function printOwing(invoice{
              let outstanding = 0;
              console.log("***********************");
              console.log("**** Customer Owes ****");
              console.log("***********************");
          }

          // ==================重構(gòu)后==================
          function printOwing(invoice{
              let outstanding = 0;
              printBanner()
          }

          function printBanner() {
              console.log("***********************");
              console.log("**** Customer Owes ****");
              console.log("***********************");
          }
          復(fù)制代碼

          函數(shù)參數(shù)化

          what

          以參數(shù)的形式傳入不同的值,消除重復(fù)函數(shù)

          where

          如果發(fā)現(xiàn)兩個函數(shù)邏輯非常相似, 只有一些字面量值不同, 可以將其合并成一個函數(shù), 以參數(shù)的形式傳入不同的值, 從而消除重復(fù)。

          how

          // ==================重構(gòu)前==================

          // 點擊異常項
          clickFaultsItem(item){
              this.$u.route({
                  url:'xxx',
                  params:{
                      id: item.id,
                      type'異常'
                  }
              })
          }

          // 點擊正常項
          clickNormalItem(item){
              this.$u.route({
                  url:'xxx',
                  params:{
                      id: item.id,
                      type'正常'
                  }
              })
          }

          // ==================重構(gòu)后==================
          clickItem(id, type){
               this.$u.route({
                  url:'xxx',
                  params:{id, type}
              })
          }
          復(fù)制代碼

          使用策略模式替換“胖”分支

          what

          使用策略模式替換“胖胖”的if-else或者switch-case

          where

          當(dāng)if-else或者switch-case分支過多時可以使用策略模式將各個分支獨立出來

          how

          // ==================重構(gòu)前==================
          function getPrice(tag, originPrice{
              // 新人價格
              if(tag === 'newUser') {
                  return originPrice > 50.1 ? originPrice - 50 : originPrice
              }
              // 返場價格
              if(tag === 'back') {
                   return originPrice > 200 ? originPrice - 50 : originPrice
              }
              // 活動價格
              if(tag === 'activity') {
                  return originPrice > 300 ? originPrice - 100 : originPrice
              }
          }

          // ==================重構(gòu)后==================
          const priceHandler = {
              newUser(originPrice){
                  return originPrice > 50.1 ? originPrice - 50 : originPrice
              },
              back(originPrice){
                  return originPrice > 200 ? originPrice - 50 : originPrice
              },
              activity(originPrice){
                   return originPrice > 300 ? originPrice - 100 : originPrice
              }
          }

          function getPrice(tag, originPrice){
              return priceHandler[tag](originPrice)
          }
          復(fù)制代碼

          提煉變量

          what

          提煉局部變量替換表達式

          where

          一個表達式有可能非常復(fù)雜且難以閱讀。這種情況下, 可以提煉出一個局部變量幫助我們將表達式分解為比較容易管理的形式 ,這樣的變量在調(diào)試時也很方便。

          how

          // ==================重構(gòu)前==================
          function price(order{
              //價格 = 商品原價 - 數(shù)量滿減價 + 運費
              return order.quantity * order.price -
              Math.max(0, order.quantity - 500) * order.price * 0.05 +
              Math.min(order.quantity * order.price * 0.1100);
          }

          // ==================重構(gòu)后==================
          function price(order{
              const basePrice = order.quantity * order.price;
              const quantityDiscount = Math.max(0, order.quantity - 500) * order.price * 0.05;
              const shipping = Math.min(basePrice * 0.1100);
              return basePrice - quantityDiscount + shipping;
          }
          復(fù)制代碼

          內(nèi)聯(lián)變量

          what

          用變量右側(cè)表達式消除變量,這是提煉變量的逆操作

          where

          當(dāng)變量名字并不比表達式本身更具表現(xiàn)力時可以采取該方法

          how

          // ==================重構(gòu)前==================
          let basePrice = anOrder.basePrice;
          return (basePrice > 1000);

          // ==================重構(gòu)后==================
          return anOrder.basePrice > 1000
          復(fù)制代碼

          封裝變量

          what

          將變量封裝起來,只允許通過函數(shù)訪問

          where

          對于所有可變的數(shù)據(jù), 只要它的作用域超出單個函數(shù),就可以采用封裝變量的方法。數(shù)據(jù)被使用得越廣, 就越是值得花精力給它一個體面的封裝。

          how

          // ==================重構(gòu)前==================
          let defaultOwner = {firstName"Martin"lastName"Fowler"};
          // 訪問
          spaceship.owner = defaultOwner;
          // 賦值
          defaultOwner = {firstName"Rebecca"lastName"Parsons"};

          // ==================重構(gòu)后==================
          function getDefaultOwner() {return defaultOwner;}
          function setDefaultOwner(arg{defaultOwner = arg;}
          // 訪問
          spaceship.owner = getDefaultOwner();
          // 賦值
          setDefaultOwner({firstName"Rebecca"lastName"Parsons"});
          復(fù)制代碼

          拆分階段

          what

          把一大段行為拆分成多個順序執(zhí)行的階段

          where

          當(dāng)看見一段代碼在同時處理兩件不同的事, 可以把它拆分成各自獨立的模塊, 因為這樣到了需要修改的時候, 就可以單獨處理每個模塊。

          how

          // ==================重構(gòu)前==================
          function priceOrder(product, quantity, shippingMethod{
              const basePrice = product.basePrice * quantity;
              
              const discount = Math.max(quantity - product.discountThreshold, 0)
              * product.basePrice * product.discountRate;
              
              const shippingPerCase = (basePrice > shippingMethod.discountThreshold)
              ? shippingMethod.discountedFee : shippingMethod.feePerCase;
              
              const shippingCost = quantity * shippingPerCase;
              
              const price = basePrice - discount + shippingCost;
              return price;
          }

          /*
          該例中前兩行代碼根據(jù)商品信息計算訂單中與商品相關(guān)的價格, 隨后的兩行則根據(jù)配送信息計算配送成本。
          將這兩塊邏輯相對獨立后,后續(xù)如果修改價格和配送的計算邏輯則只需修改對應(yīng)模塊即可。
          */


          // ==================重構(gòu)后==================
          function priceOrder(product, quantity, shippingMethod{
              const priceData = calculatePricingData(product, quantity);
              return applyShipping(priceData, shippingMethod);
          }
          // 計算商品價格
          function calculatePricingData(product, quantity{
              const basePrice = product.basePrice * quantity;
              const discount = Math.max(quantity - product.discountThreshold, 0)
              * product.basePrice * product.discountRate;
              
              return {basePrice, quantity, discount};
          }
          // 計算配送價格
          function applyShipping(priceData, shippingMethod{
              const shippingPerCase = (priceData.basePrice > shippingMethod.discountThreshold)
              ? shippingMethod.discountedFee : shippingMethod.feePerCase;
              const shippingCost = priceData.quantity * shippingPerCase;
              
              return priceData.basePrice - priceData.discount + shippingCost;
          }
          復(fù)制代碼

          拆分循環(huán)

          what

          將一個循環(huán)拆分成多個循環(huán)

          where

          當(dāng)遇到一個身兼數(shù)職的循環(huán)時可以將循環(huán)拆解,讓一個循環(huán)只做一件事情, 那就能確保每次修改時你只需要理解要修改的那塊代碼的行為就可以了。該行為可能會被質(zhì)疑,因為它會迫使你執(zhí)行兩次甚至多次循環(huán),實際情況是,即使處理的列表數(shù)據(jù)更多一些,循環(huán)本身也很少成為性能瓶頸,更何況拆分出循環(huán)來通常還使一些更強大的優(yōu)化手段變得可能。

          how

          // ==================重構(gòu)前==================
          const people = [
              { age20salary10000 },
              { age21salary15000 },
              { age22salary18000 }
          ]

          let youngest = people[0] ? people[0].age : Infinity;
          let totalSalary = 0;
          for (const p of people) {
              // 查找最年輕的人員
              if (p.age < youngest) youngest = p.age;
              // 計算總薪水
              totalSalary += p.salary;
          }
          console.log(`youngestAge: ${youngest}, totalSalary: ${totalSalary}`);

          // ==================重構(gòu)后==================
          const people = [
              { age20salary10000 },
              { age21salary15000 },
              { age22salary18000 }
          ]

          let totalSalary = 0;
          for (const p of people) {
              // 只計算總薪資
              totalSalary += p.salary;
          }
          let youngest = people[0] ? people[0].age : Infinity;
          for (const p of people) {
              // 只查找最年輕的人員
              if (p.age < youngest) youngest = p.age;

          console.log(`youngestAge: ${youngest}, totalSalary: ${totalSalary}`);

          // ==================提煉函數(shù)==================
          const people = [
              { age20salary10000 },
              { age21salary15000 },
              { age22salary18000 }
          ]

          console.log(`youngestAge: ${youngestAge()}, totalSalary: ${totalSalary()}`);

          function totalSalary() {
              let totalSalary = 0;
              for (const p of people) {
                  totalSalary += p.salary;
              }
              return totalSalary;

          function youngestAge() {
              let youngest = people[0] ? people[0].age : Infinity;
              for (const p of people) {
                  if (p.age < youngest) youngest = p.age;
              }
              return youngest;
          }

          // ==================使用工具類進一步優(yōu)化==================
          const people = [
              { age20salary10000 },
              { age21salary15000 },
              { age22salary18000 }
          ]

          console.log(`youngestAge: ${youngestAge()}, totalSalary: ${totalSalary()}`);

          function totalSalary() {
              return people.reduce((total,p) => total + p.salary, 0);
          }
          function youngestAge() {
              return Math.min(...people.map(p => p.age));
          }
          復(fù)制代碼

          拆分變量

          what

          將一個變量拆分成兩個或多個變量

          where

          如果變量承擔(dān)多個責(zé)任, 它就應(yīng)該被替換為多個變量, 每個變量只承擔(dān)一個責(zé)任。

          how

          // ==================重構(gòu)前==================
          let temp = 2 * (height + width);
          console.log(temp);
          temp = height * width;
          console.log(temp);

          // ==================重構(gòu)后==================
          const perimeter = 2 * (height + width);
          console.log(perimeter);
          const area = height * width;
          console.log(area);
          復(fù)制代碼

          分解條件表達式

          what

          將條件表達式提煉成函數(shù)

          where

          在帶有復(fù)雜條件邏輯的函數(shù)中,往往可以將原函數(shù)中對應(yīng)的代碼改為調(diào)用新函數(shù)。

          對于條件邏輯, 將每個分支條件分解成新函數(shù)可以帶來的好處:

          • 提高可讀性
          • 可以突出條件邏輯, 更清楚地表明每個分支的作用
          • 突出每個分支的原因

          how

          // ==================重構(gòu)前==================
          // 計算一件商品的總價,該商品在冬季和夏季的單價是不同的
          if (!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd))
          charge = quantity * plan.summerRate;
          else
          charge = quantity * plan.regularRate + plan.regularServiceCharge;

          // ==================重構(gòu)后==================
          if (summer())
              charge = summerCharge();
          else
              charge = regularCharge();

          function summer() {
              return !aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd);
          }
          function summerCharge() {
              return quantity * plan.summerRate;
          }
          function regularCharge() {
              return quantity * plan.regularRate + plan.regularServiceCharge;
          }

          // 進一步優(yōu)化(使用三元運算符)
          charge = summer() ? summerCharge() : regularCharge();
          function summer() {
              return !aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd);
          }
          function summerCharge() {
              return quantity * plan.summerRate;
          }
          function regularCharge() {
              return quantity * plan.regularRate + plan.regularServiceCharge;
          }
          復(fù)制代碼

          合并條件表達式

          what

          將多個條件表達式合并

          where

          當(dāng)發(fā)現(xiàn)這樣一串條件檢查:檢查條件各不相同, 最終行為卻一致。如果發(fā)現(xiàn)這種情況,就應(yīng)該使用“邏輯或”和“邏輯與”將它們合并為一個條件表達式。

          how

          // ==================重構(gòu)前==================
          if (anEmployee.seniority < 2return 0;
          if (anEmployee.monthsDisabled > 12return 0;
          if (anEmployee.isPartTime) return 0;

          // ==================重構(gòu)后==================
          if (isNotEligableForDisability()) return 0;
          function isNotEligableForDisability() {
              return ((anEmployee.seniority < 2)
                      || (anEmployee.monthsDisabled > 12)
                      || (anEmployee.isPartTime));
          }
          復(fù)制代碼

          以衛(wèi)語句取代嵌套條件表達式

          what

          如果某個條件極其罕見,就應(yīng)該單獨檢查該條件,并在該條件為真時立刻從函數(shù)中返回。這樣的單獨檢查常常被稱為“衛(wèi)語句”(guard clauses)。

          where

          如果使用if-else結(jié)構(gòu),你對if分支和else分支的重視是同等的。這樣的代碼結(jié)構(gòu)傳遞給閱讀者的消息就是:各個分支有同樣的重要性。衛(wèi)語句就不同了,它告訴閱讀者:“這種情況不是本函數(shù)的核心邏輯所關(guān)心的, 如果它真發(fā)生了,請做一些必要的整理工作,然后退出?!?為了傳遞這種信息可以使用衛(wèi)語句替換嵌套結(jié)構(gòu)。

          how

          // ==================重構(gòu)前==================
          function payAmount(employee{
              let result;
              if(employee.isSeparated) {
                  result = {amount0reasonCode:"SEP"};
              }
              else {
                  if (employee.isRetired) {
                      result = {amount0reasonCode"RET"};
                  }
                  else {
                      result = someFinalComputation();
                  }
              }
              return result;
          }

          // ==================重構(gòu)后==================
          function payAmount(employee{
              if (employee.isSeparated) return {amount0reasonCode"SEP"};
              if (employee.isRetired) return {amount0reasonCode"RET"};
              return someFinalComputation();
          }
          復(fù)制代碼

          將查詢函數(shù)和修改函數(shù)分離

          what

          將查詢動作從修改動作中分離出來的方式

          where

          如果遇到一個“既有返回值又有副作用”的函數(shù),此時可以將查詢動作從修改動作中分離出來。

          how

          // ==================重構(gòu)前==================
          function alertForMiscreant (people{
              for (const p of people) {
                  if (p === "Don") {
                      setOffAlarms();
                      return "Don";
                  }
                  if (p === "John") {
                      setOffAlarms();
                      return "John";}
              }
              return "";
          }
          // 調(diào)用方
          const found = alertForMiscreant(people);

          // ==================重構(gòu)后==================
          function findMiscreant (people{
              for (const p of people) {
                  if (p === "Don") {
                      return "Don";
                  }
                  if (p === "John") {
                      return "John";
                  }
              }
              return "";
          }
          function alertForMiscreant (people{
              if (findMiscreant(people) !== "") setOffAlarms();
          }
          // 調(diào)用方
          const found = findMiscreant(people);
          alertForMiscreant(people);
          復(fù)制代碼
          關(guān)于本文

          作者:俺是誰

          https://juejin.cn/post/7131211363493347335

          最后



          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
          回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會很認真的解答喲!
          回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對你有幫助,在看」是最大的支持
           》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持


          瀏覽 48
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  日批视频免费看 | 亚洲天堂视频一区 | 国产熟妇 码视频户外直播 | 欧洲A亚洲A免费视频 | 国内9l 自拍九色啦视频 |