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

          讓同事贊不絕口的代碼原來長這樣啊

          共 6792字,需瀏覽 14分鐘

           ·

          2021-02-05 08:52

          文/會編程的銀豬

          閱讀本文需要?3分鐘

          網(wǎng)上有不少關(guān)于 JS 編寫優(yōu)化建議,這里我根據(jù)自己的經(jīng)驗(yàn)提出一些比較有用的意見。

          1. 按強(qiáng)類型風(fēng)格寫代碼

          JS 是弱類型的,但是寫代碼的時候不能太隨意,寫得太隨意也體現(xiàn)了編碼風(fēng)格不好。下面分點(diǎn)說明:
          (1)定義變量的時候要指明類型,告訴 JS 解釋器這個變量是什么數(shù)據(jù)類型的,而不要讓解釋器去猜,例如不好的寫法:

          var num,
          str,
          obj;

          聲明了三個變量,但其實(shí)沒什么用,因?yàn)榻忉屍鞑恢浪鼈兪鞘裁搭愋偷模玫膶懛☉?yīng)該是這樣的:

          var num = 0,
          str = '',
          obj = null;

          定義變量的時候就給他一個默認(rèn)值,這樣不僅方便了解釋器,也方便了閱讀代碼的人,他會在心里有數(shù)——知道這些變量可能會當(dāng)作什么用。

          (2)不要隨意地改變變量的類型,例如下面代碼:

          var num = 5;
          num = "-" + num;

          第 1 行它是一個整型,第 2 行它變成了一個字符串。因?yàn)?JS 最終都會被解釋成匯編的語言,匯編語言變量的類型肯定是要確定的,你把一個整型的改成了字符串,那解釋器就得做一些額外的處理。并且這種編碼風(fēng)格是不提倡的,有一個變量第 1 行是一個整型,第 10 行變成了一個字符串,第 20 行又變成了一個 object,這樣就讓閱讀代碼的人比較困惑,上面明明是一個整數(shù),怎么突然又變成一個字符串了。好的寫法應(yīng)該是再定義一個字符串的變量:

          var num = 5;
          var sign = "-" + num;

          (3)函數(shù)的返回類型應(yīng)該是要確定的,例如下面不確定的寫法:

          function getPrice(count){
          if(count < 0) return "";
          else return count * 100;
          }

          getPrice 這個函數(shù)有可能返回一個整數(shù),也有可能返回一個空的字符串。這樣寫也不太好,雖然它是符合 JS 語法的,但這種編碼風(fēng)格是不好的。使用你這個函數(shù)的人會有點(diǎn)無所適從,不敢直接進(jìn)行加減乘除,因?yàn)槿绻祷刈址M(jìn)行運(yùn)算的話值就是 NaN 了。函數(shù)的返回類型應(yīng)該是要確定的,如下面是返回整型:

          function getPrice(count){
          if(count < 0) return -1;
          else return count * 100;
          }

          然后告訴使用者,如果返回-1 就表示不合法。如果類型確定,解釋器也不用去做一些額外的工作,可以加快運(yùn)行速度。

          2. 減少作用域查找

          (1)不要讓代碼暴露在全局作用域下
          例如以下運(yùn)行在全局作用域的代碼:

          <script>
          var map = document.querySelector("#my-map");
          map.style.height = "600px";
          script>

          有時候你需要在頁面直接寫一個 script,要注意在一個 script 標(biāo)簽里面,代碼的上下文都是全局作用域的,由于全局作用域比較復(fù)雜,查找比較慢。例如上面的 map 變量,第二行在使用的時候,需要在全局作用域查找一下這個變量,假設(shè) map 是在一個循環(huán)里面使用,那可能就會有效率問題了。所以應(yīng)該要把它搞成一個局部的作用域:

          <script>
          !function(){
          var map = document.querySelector("#my-map");
          map.style.height = "600px";
          }()
          script>

          上面用了一個 function 制造一個局部作用域,也可以用 ES6 的塊級作用域。由于 map 這個變量直接在當(dāng)前的局部作用域命中了,所以就不用再往上一級的作用域(這里是全局作用域)查找了,而局部作用域的查找是很快的。同時直接在全局作用域定義變量,會污染 window 對象。

          (2)不要濫用閉包
          閉包的作用在于可以讓子級作用域使用它父級作用域的變量,同時這些變量在不同的閉包是不可見的。這樣就導(dǎo)致了在查找某個變量的時候,如果當(dāng)前作用域找不到,就得往它的父級作用域查找,一級一級地往上直到找到了,或者到了全局作用域還沒找到。因此如果閉包嵌套得越深,那么變量查找的時間就越長。如下:

          function getResult(count){
          count++;
          function process(){
          var factor = 2;
          return count * factor - 5;
          }
          return process();
          }

          上面的代碼定義了一個 process 函數(shù),在這個函數(shù)里面 count 變量的查找時間要高于局部的 factor 變量。其實(shí)這里不太適合用閉包,可以直接把 count 傳給 process:

          function getResult(count){
          count++;
          function process(count){
          var factor = 2;
          return count * factor - 5;
          }
          return process(count);
          }

          這樣 count 的查找時間就和 factor 一樣,都是在當(dāng)前作用域直接命中。這個就啟示我們?nèi)绻硞€全局變量需要頻繁地被使用的時候,可以用一個局部變量緩存一下,如下:

          var url = "";
          if(window.location.protocal === "https:"){
          url = "wss://xxx.com" + window.location.pathname + window.location.search;
          }

          頻繁地使用了 window.location 對象,所以可以先把它緩存一下:

          var url = "";
          var location = window.location;
          if(location.protocal === "https:"){
          url = "wss://xxx.com" + location.pathname + location.search;
          }

          搞成了一個局變變量,這樣查找就會明顯快于全局的查找,代碼也可以寫少一點(diǎn)。

          3. 避免==的使用

          這里你可能會有疑問了,有些人喜歡用==,有些人喜歡用===,大家的風(fēng)格不一樣,你為什么要強(qiáng)制別人用===呢?習(xí)慣用==的人,不能僅僅是因?yàn)?=比===少敲了一次鍵盤。為什么不提倡用==呢?

          (1)如果你確定了變量的類型,那么就沒必要使用==了,如下:

          if(typeof num != "undefined"){

          }
          var num = parseInt(value);
          if(num == 10){

          }

          上面的兩個例子都是確定類型的,一個是字符串,一個是整數(shù)。就沒必要使用==了,直接用===就可以了。

          (2)如果類型不確定,那么應(yīng)該手動做一下類型轉(zhuǎn)換,而不是讓別人或者以后的你去猜這里面有類型轉(zhuǎn)換,如下:

          var totalPage = "5";
          if(parseInt(totalPage) === 1){

          }

          (3)使用==在 JSLint 檢查的時候是不通過的:

          if(a == b){

          }

          如下 JSLint 的輸出:

          Expected ‘===’ and instead saw ‘==’.
          if(a == b){

          (4)并且使用==可能會出現(xiàn)一些奇怪的現(xiàn)象,這些奇怪的現(xiàn)象可能會給代碼埋入隱患:

          null == undefined          //true
          '' == '0' //false
          0 == '' //true
          0 == '0' //true
          '
          '
          == 0 //true
          new String("abc") == "abc" //true
          new Boolean(true) == true //true
          true == 1 //true

          上面的比較在用===的時候都是 false,這樣才是比較合理的。例如第一點(diǎn) null 居然會等于 undefined,就特別地奇怪,因?yàn)?null 和 undefined 是兩個毫無關(guān)系的值,null 應(yīng)該是作為初始化空值使用,而 undefined 是用于檢驗(yàn)?zāi)硞€變量是否未定義。這和第 1 點(diǎn)介紹強(qiáng)類型的思想是相通的。

          4. 合并表達(dá)式

          如果用 1 句代碼就可以實(shí)現(xiàn) 5 句代碼的功能,那往往 1 句代碼的執(zhí)行效率會比較高,并且可讀性可能會更好

          (1)用三目運(yùn)算符取代簡單的 if-else
          如上面的 getPrice 函數(shù):

          function getPrice(count){
          if(count < 0) return -1;
          else return count * 100;
          }

          可以改成:

          function getPrice(count){
          return count < 0 ? return -1 : count * 100;
          }

          這個比寫一個 if-else 看起來清爽多了。當(dāng)然,如果你寫了 if-else,壓縮工具也會幫你把它改三目運(yùn)算符的形式:

          function getPrice(e){return 0>e?-1:100*e}

          (2)連等
          連等是利用賦值運(yùn)算表達(dá)式會返回所賦的值,并且執(zhí)行順序是從右到左的,如下:

          overtime = favhouse = listingDetail = {...}

          有時候你會看到有人這樣寫:

          var age = 0;
          if((age = +form.age.value) >= 18){
          console.log("你是成年人");
          } else {
          consoe.log("小朋友,你還有" + (18 - age) + "就成年了");
          }

          也是利用了賦值表達(dá)式會返回一個值,在 if 里面賦值的同時用它的返回值做判斷,然后 else 里面就已經(jīng)有值了。上面的+號把字符串轉(zhuǎn)成了整數(shù)。

          (3)自增
          利用自增也可以簡化代碼。如下,每發(fā)出一條消息,localMsgId 就自增 1:

          chatService.sendMessage(localMsgId++, msgContent);

          5. 減少魔數(shù)

          例如,在某個文件的第 800 行,冒出來了一句:

          dialogHandler.showQuestionNaire("seller", "sell", 5, true);

          就會讓人很困惑了,上面的四個常量分別代表什么呢,如果我不去查一個那個函數(shù)的變量說明就不能夠很快地意會到這些常量分別有什么用。這些意義不明的常量就叫“魔數(shù)”。所以最好還是給這些常量取一個名字,特別是在一些比較關(guān)鍵的地方。例如上面的代碼可改成:

          var naireType = "seller",
          dialogType = "sell",
          questionsCount = 5,
          reloadWindow = true;

          naireHandler.showNaire(naireType, dialogType, questionsCount, reloadWindow);

          這樣意義就很明顯了。

          6. 使用 ES6 簡化代碼

          ES6 已經(jīng)發(fā)展很多年了,兼容性也已經(jīng)很好了。恰當(dāng)?shù)厥褂茫梢宰尨a更加地簡潔優(yōu)雅。

          (1)使用箭頭函數(shù)取代小函數(shù)
          有很多使用小函數(shù)的場景,如果寫個 function,代碼起碼得寫 3 行,但是用箭頭函數(shù)一行就搞定了,例如實(shí)現(xiàn)數(shù)組從大到小排序:

          var nums = [4, 8, 1, 9, 0];
          nums.sort(function(a, b){
          return b - a;
          });
          //輸出[9, 8, 4, 1, 0]

          如果用箭頭函數(shù),排序只要一行就搞定了:

          var nums = [4, 8, 1, 9, 0];``nums.sort(a, b => b - a);

          代碼看起來簡潔多了,還有 setTimeout 里面經(jīng)常會遇到只要執(zhí)行一行代碼就好了,寫個 function 總感覺有點(diǎn)麻煩,用字符串的方式又不太好,所以這種情況用箭頭函數(shù)也很方便:

          setTimeout(() => console.log("hi"), 3000)

          箭頭函數(shù)在 C++/Java 等其它語言里面叫做 Lambda 表達(dá)式,Ruby 比較早就有這種語法形式了,后來 C++/Java 也實(shí)現(xiàn)了這種語法。當(dāng)然箭頭函數(shù)或者 Lambda 表達(dá)式不僅適用于這種一行的,多行代碼也可以,不過在一行的時候它的優(yōu)點(diǎn)才比較明顯。

          (2)使用 ES6 的 class
          雖然 ES6 的 class 和使用 function 的 prototype 本質(zhì)上是一樣的,都是用的原型。但是用 class 可以減少代碼量,同時讓代碼看起來更加地高大上,使用 function 要寫這么多:

          function Person(name, age){
          this.name = name;
          this.age = age;
          }

          Person.prototype.addAge = function(){
          this.age++;
          };

          Person.prototype.setName = function(name){
          this.name = name;
          };

          使用 class 代碼看加地簡潔易懂:

          class Person{
          constructor(name, age){
          this.name = name;
          this.age = age;
          }
          addAge(){
          this.age++;
          }
          setName(name){
          this.name = name;
          }
          }

          并且 class 還可以很方便地實(shí)現(xiàn)繼承、靜態(tài)的成員函數(shù),就不需要自己再去通過一些技巧去實(shí)現(xiàn)了。

          (3)字符串拼接
          以前要用+號拼接:

          var tpl =
          '
          ' +
          ' 1' +
          '
          '
          ;

          現(xiàn)在只要用兩個反引號“`”就可以了:

          var tpl =
          `

          1

          `
          ;

          另外反引號還支持占位替換,原本你需要:

          var page = 5,
          type = encodeURIComponet("#js");
          var url = "/list?page=" + page + "&type=" + type;

          現(xiàn)在只需要:

          var url = `/list?page=${page}&type=${type}`;

          就不用使用+號把字符串拆散了。

          (4)塊級作用域變量
          塊級作用域變量也是 ES6 的一個特色,下面的代碼是一個任務(wù)隊(duì)列的模型抽象:

          var tasks = [];
          for(var i = 0; i < 4; i++){
          tasks.push(function(){
          console.log("i is " + i);
          });
          }
          for(var j = 0; j < tasks.length; j++){
          tasks[j]();
          }

          但是上面代碼的執(zhí)行輸出是 4,4,4,4,并且不是想要輸出:0,1,2,3,所以每個 task 就不能取到它的 index 了,這是因?yàn)殚]包都是用的同一個 i 變量,i 已經(jīng)變成 4 了,所以執(zhí)行閉包的時候就都是 4 了。那怎么辦呢?可以這樣解決:

          var tasks = [];
          for(var i = 0; i < 4; i++){
          !function(k){
          tasks.push(function(){
          console.log("i is " + k);
          });
          }(i);
          }
          for(var j = 0; j < tasks.length; j++){
          tasks[j]();
          }

          把 i 賦值給了 k,由于 k 它是一個 function 的一個參數(shù),每次執(zhí)行函數(shù)的時候,肯定會實(shí)例化新的 k,所以每次的 k 都是不同的變量,這樣就輸出就正常了。但是代碼看起來有點(diǎn)別扭,如果用 ES6,只要把 var 改成 let 就可以了:

          var tasks = [];
          for(let i = 0; i <= 4; i++){
          tasks.push(function(){
          console.log("i is " + i);
          });
          }
          for(var j = 0; j < tasks.length; j++){
          tasks[j]();
          }

          只改動了 3 個字符就達(dá)到了目的。因?yàn)?for 循環(huán)里面有個大括號,大括號就是一個獨(dú)立的作用域,let 定義的變量在獨(dú)立的作用域里面它的值也是獨(dú)立的。當(dāng)然即使沒寫大括號 for 循環(huán)執(zhí)行也是獨(dú)立的。除了以上幾點(diǎn),ES6 還有其它一些比較好用的功能,如 Object 的 assign,Promise 等,也是可以幫助寫出簡潔高效的代碼。以上列了我自己在實(shí)際寫代碼過程中遇到的一些問題和一些個人認(rèn)為比較重要的方面,其它的還有變量命名、縮進(jìn)、注釋等,這里就不提及了。寫代碼的風(fēng)格也體現(xiàn)了編程的素養(yǎng),有些人的代碼看起來非常地干凈利落,而有些人的代碼看起來讓人比較痛苦。這種編程素質(zhì)的提升需要有意識地去做一些改進(jìn),有些人雖然代碼寫得很爛,但是他自己并不覺得有什么問題。這就需要多去學(xué)下別人的代碼,甚至學(xué)一下其它語言的書寫,兩者一比較就能發(fā)現(xiàn)差異,或者看下這方面的書,像什么代碼大全之類的。

          瀏覽 24
          點(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>
                  一本大道HEYZO无码专区 一道本一区二区三区免费视频 | 亚洲福利一区 | 成人18禁网站 | 国产一呦二呦三呦 | 免费国产黄片在线看 |