<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 開(kāi)發(fā)者常犯的 9 個(gè)錯(cuò)誤?

          共 7114字,需瀏覽 15分鐘

           ·

          2020-10-09 11:16

          JavaScript 是一種給網(wǎng)頁(yè)添加功能和交互的腳本語(yǔ)言,對(duì)于使用不同編程語(yǔ)言的初學(xué)者來(lái)說(shuō)很容易理解。有了一些教程,你就可以馬上開(kāi)始使用它了。

          但很多初學(xué)者都會(huì)犯一些常見(jiàn)的錯(cuò)誤。在這篇文章中,我們將介紹 9 個(gè)常見(jiàn)的錯(cuò)誤(或者說(shuō)不好的實(shí)踐)以及它們的解決方案,幫助你成為更好的 JavaScript 開(kāi)發(fā)者。

          將賦值操作符(=)和相等操作符(==,===)混為一談

          正如名稱(chēng)所示,賦值操作符是用來(lái)給變量賦值的。開(kāi)發(fā)者常常把它與相等操作符混淆。

          舉個(gè)例子:

          const?name?=?"javascript";
          if?((name?=?"nodejs"))?{
          ????console.log(name);
          }
          //?output?-?nodejs

          本例中,不是比較 name 變量和 ?nodejs ?字符串,而是為 name 賦值 ?nodejs,并將 ?nodejs ?輸出到控制臺(tái)。

          在 JavaScript 中,兩個(gè)等號(hào)(==)和三個(gè)等號(hào)(===)是比較操作符。

          對(duì)于上述代碼,可以使用以下方法比較值:

          const?name?=?"javascript";
          if?(name?==?"nodejs")?{
          ????console.log(name);
          }
          //?no?output
          //?OR
          if?(name?===?"nodejs")?{
          ????console.log(name);
          }
          //?no?output

          這兩個(gè)比較操作符的區(qū)別是:兩個(gè)等號(hào)執(zhí)行寬松的比較,三個(gè)等號(hào)執(zhí)行嚴(yán)格的比較。

          大致比較時(shí),只比較值。但嚴(yán)格地說(shuō),值和數(shù)據(jù)類(lèi)型都是要比較的。

          下面的代碼更好地解釋了這一點(diǎn):

          const?number?=?"1";
          console.log(number?==?1);
          //?true
          console.log(number?===?1);
          //?false

          給變量 number 賦值 1。如果將 number 用雙等號(hào)與 1 進(jìn)行比較,會(huì)返回 true,因?yàn)閮蓚€(gè)值都是 1。

          然而,在用三個(gè)等號(hào)的情況下,因?yàn)槊總€(gè)值的數(shù)據(jù)類(lèi)型不同,所以返回 false。

          預(yù)期的回調(diào)是同步的

          在 JavaScript 里,用回調(diào)方法處理異步操作。然而,Promises 和 async/await 是處理異步操作的首選方法,因?yàn)槎啻位卣{(diào)會(huì)導(dǎo)致回調(diào)地獄。

          回調(diào)是不同步的。在延遲執(zhí)行完成操作之后,它們作為一個(gè)函數(shù)被調(diào)用。

          例如,全局 ?setTimeout ?接收回調(diào)函數(shù)作為第一個(gè)參數(shù),接收持續(xù)時(shí)間(毫秒)作為第二個(gè)參數(shù):

          function?callback()?{
          ????console.log("I?am?the?first");
          }
          setTimeout(callback,?300);
          console.log("I?am?the?last");
          //?output
          //?I?am?the?last
          //?I?am?the?first

          在 300ms 之后,調(diào)用回調(diào)函數(shù)。但是代碼的其余部分在完成前運(yùn)行,因此,最后一個(gè) console.log 將首先運(yùn)行。

          開(kāi)發(fā)者經(jīng)常犯的一個(gè)錯(cuò)誤就是誤解了回調(diào)是同步的,比如,認(rèn)為回調(diào)函數(shù)一個(gè)值用于其他操作。

          錯(cuò)誤在于:

          function?addTwoNumbers()?{
          ????let?firstNumber?=?5;
          ????let?secondNumber;
          ????setTimeout(function?()?{
          ????????secondNumber?=?10;
          ????},?200);
          ????console.log(firstNumber?+?secondNumber);
          }
          addTwoNumbers();
          //?NaN

          由于 ?secondNumber ?不確定,所以輸出 ?NaN。運(yùn)行 ?firstNumber+secondNumber ?的時(shí)候,仍然沒(méi)有定義 ?secondNumber,因?yàn)??setTimeout ?函數(shù)會(huì)在 200ms 之后執(zhí)行回調(diào)。

          最好的方法是在回調(diào)函數(shù)中執(zhí)行剩余的代碼:

          function?addTwoNumbers()?{
          ????let?firstNumber?=?5;
          ????let?secondNumber;
          ????setTimeout(function?()?{
          ????????secondNumber?=?10;
          ????????console.log(firstNumber?+?secondNumber);
          ????},?200);
          }
          addTwoNumbers();
          //?15

          this 指代錯(cuò)誤

          在 JavaScript 中,this 是一個(gè)常被誤解的概念。在 JavaScript 使用 this,你需要理解它的作用是什么,這里的 this 跟其他語(yǔ)言中的 this 用法不同。

          以下是關(guān)于 this 的常見(jiàn)錯(cuò)誤的示例:

          const?obj?=?{
          ????name:?"JavaScript",
          ????printName:?function?()?{
          ????????console.log(this.name);
          ????},
          ????printNameIn2Secs:?function?()?{
          ????????setTimeout(function?()?{
          ????????????console.log(this.name);
          ????????},?2000);
          ????},
          };
          obj.printName();
          //?JavaScript
          obj.printNameIn2Secs();
          //?undefined

          第一個(gè)結(jié)果是 ?JavaScript,因?yàn)??this.name ?正確地指向?qū)ο蟮?name 屬性。第二個(gè)結(jié)果是 ?undefined,因?yàn)??this 未指代對(duì)象的屬性(包括 name)。

          原因在于 ?this ?依賴(lài)于正在調(diào)用該函數(shù)的對(duì)象。每個(gè)函數(shù)都有一個(gè) ?this ?變量,但是它的指向由調(diào)用 ?this ?的對(duì)象決定。

          bj.printName() ?的 ?this直接指向 ?obj。obj.printNameIn2Secs ?的 ?this ?直接指向 ?obj。然而,但是 ?this 在回調(diào)函數(shù) ?setTimeout ?中沒(méi)有指向任何對(duì)象,因?yàn)闆](méi)有任何對(duì)象調(diào)用它。

          如果一個(gè)對(duì)象調(diào)用 ?setTimeout,則執(zhí)行obj.setTimeout...。因?yàn)闆](méi)有對(duì)象調(diào)用這個(gè)函數(shù),所以使用默認(rèn)對(duì)象(即 ?window)。

          window ?上沒(méi)有 ?name,故返回 ?undefined。

          在 ?setTimeout ?中保留 ?this ?指代的最好方法是使用 ?bind、callapply 或箭頭功能(在 ES6 中引入)。不同于常規(guī)函數(shù),箭頭函數(shù)不創(chuàng)建自己的 ?this。

          所以,下面的代碼會(huì)保留 ?this ?指代:

          const?obj?=?{
          ????name:?"JavaScript",
          ????printName:?function?()?{
          ????????console.log(this.name);
          ????},
          ????printNameIn2Secs:?function?()?{
          ????????setTimeout(()?=>?{
          ????????????console.log(this.name);
          ????????},?2000);
          ????},
          };
          obj.printName();
          //?JavaScript
          obj.printNameIn2Secs();
          //?JavaScript

          忽視對(duì)象的可變性

          JavaScript 對(duì)象中的引用數(shù)據(jù)類(lèi)型不像字符串、數(shù)字等原始數(shù)據(jù)類(lèi)型。比如,在鍵值對(duì)對(duì)象中:

          const?obj1?=?{
          ????name:?"JavaScript",
          };
          const?obj2?=?obj1;
          obj2.name?=?"programming";
          console.log(obj1.name);
          //?programming

          obj1 ?和 ?obj2 ?在內(nèi)存中指向相同的地址。

          在數(shù)組中:

          const?arr1?=?[2,?3,?4];
          const?arr2?=?arr1;
          arr2[0]?=?"javascript";
          console.log(arr1);
          //?['javascript',?3,?4]

          開(kāi)發(fā)者經(jīng)常犯的一個(gè)錯(cuò)誤是忽略了 JavaScript 的這個(gè)特性,而這將導(dǎo)致意外的錯(cuò)誤。

          如果出現(xiàn)這種情況,訪問(wèn)原始屬性的任何嘗試都會(huì)返回 ?undefined ?或者引發(fā)錯(cuò)誤。

          最好的方法是,當(dāng)你想復(fù)制一個(gè)對(duì)象的時(shí)候,總是創(chuàng)建一個(gè)新的引用。為了達(dá)到這個(gè)目的,擴(kuò)展運(yùn)算符(在 ES6 中引入的...)就是一個(gè)完美的解決方案。

          比如,在鍵值對(duì)對(duì)象中:

          const?obj1?=?{
          ????name:?"JavaScript",
          };
          const?obj2?=?{?...obj1?};
          console.log(obj2);
          //?{name:?'JavaScript'?}
          obj2.name?=?"programming";
          console.log(obj.name);
          //?'JavaScript'

          在數(shù)組中:

          const?arr1?=?[2,?3,?4];
          const?arr2?=?[...arr1];
          console.log(arr2);
          //?[2,3,4]
          arr2[0]?=?"javascript";
          console.log(arr1);
          //?[2,?3,?4]

          保存數(shù)組和對(duì)象至瀏覽器儲(chǔ)存

          使用 JavaScript 的時(shí)候,開(kāi)發(fā)者可能希望利用 ?localStorage ?來(lái)保存值。然而,一個(gè)常見(jiàn)的錯(cuò)誤是直接將數(shù)組和對(duì)象保存在 ?localStorage ?中。localStorage ?只接收字符串。

          JavaScript 將對(duì)象轉(zhuǎn)換成字符串以保來(lái)保存,其結(jié)果是對(duì)象保存為 ?[Object Object],數(shù)組保存為逗號(hào)分隔開(kāi)的字符串。

          比如:

          const?obj?=?{?name:?"JavaScript"?};
          window.localStorage.setItem("test-object",?obj);
          console.log(window.localStorage.getItem("test-object"));
          //?[Object?Object]
          const?arr?=?["JavaScript",?"programming",?45];
          window.localStorage.setItem("test-array",?arr);
          console.log(window.localStorage.getItem("test-array"));
          //?JavaScript,?programming,?45

          在保存這些對(duì)象時(shí),很難訪問(wèn)它們。例如,對(duì)于一個(gè)對(duì)象,通過(guò) ?.name ?訪問(wèn)它會(huì)導(dǎo)致錯(cuò)誤。因?yàn)??[Object Object] ?現(xiàn)在是一個(gè)字符串,而不包含 ?name ?屬性。

          通過(guò)使用 ?JSON.stringify(將對(duì)象轉(zhuǎn)換為字符串)和 ?JSON.parse(將字符串轉(zhuǎn)換為對(duì)象),可以更好地保存本地存儲(chǔ)對(duì)象和數(shù)組。通過(guò)這種方式可以輕松訪問(wèn)對(duì)象。

          上述代碼的正確版本為:

          const?obj?=?{?name:?"JavaScript"?};
          window.localStorage.setItem("test-object",?JSON.stringify(obj));
          const?objInStorage?=?window.localStorage.getItem("test-object");
          console.log(JSON.parse(objInStorage));
          //?{name:?'JavaScript'}
          const?arr?=?["JavaScript",?"programming",?45];
          window.localStorage.setItem("test-array",?JSON.stringify(arr));
          const?arrInStorage?=?window.localStorage.getItem("test-array");
          console.log(JSON.parse(arrInStorage));
          //?JavaScript,?programming,?45

          不使用默認(rèn)值

          為動(dòng)態(tài)變量設(shè)置默認(rèn)值是一個(gè)很好的預(yù)防意外錯(cuò)誤的方法。這里有一個(gè)常見(jiàn)錯(cuò)誤的例子:

          function?addTwoNumbers(a,?b)?{
          ????console.log(a?+?b);
          }
          addTwoNumbers();
          //?NaN

          由于 ?a ?為 ?undefined,b 也為 ?undefined,因此結(jié)果為 ?NaN。你可以使用默認(rèn)值防止類(lèi)似錯(cuò)誤,比如:

          function?addTwoNumbers(a,?b)?{
          ????if?(!a)?a?=?0;
          ????if?(!b)?b?=?0;
          ????console.log(a?+?b);
          }
          addTwoNumbers();
          //?0

          此外,可以在 ES6 中這樣使用默認(rèn)值:

          function?addTwoNumbers(a?=?0,?b?=?0)?{
          ????console.log(a?+?b);
          }
          addTwoNumbers();
          //?0

          此示例雖小,但強(qiáng)調(diào)了默認(rèn)值的重要性。

          另外,如果沒(méi)有提供期望,開(kāi)發(fā)者可以提供一個(gè)錯(cuò)誤或者警告信息。

          變量命名錯(cuò)誤

          是的,開(kāi)發(fā)者還是會(huì)犯這個(gè)錯(cuò)誤。命名是困難的,但開(kāi)發(fā)人員沒(méi)有其他選擇。注解和命名變量一樣,都是編程的好習(xí)慣。

          比如:

          function?total(discount,?p)?{
          ????return?p?*?discount
          }

          變量 ?discount ?沒(méi)問(wèn)題,但是 ?p ?或者 ?total ?呢?是什么的 ?total?最好是:

          function?totalPrice(discount,?price)?{
          ????return?discount?*?price
          }

          對(duì)變量進(jìn)行適當(dāng)?shù)拿浅V匾?,因?yàn)樵谔囟ǖ臅r(shí)間和將來(lái),可能有別的開(kāi)發(fā)者使用這個(gè)代碼庫(kù)。

          適當(dāng)?shù)孛兞繒?huì)讓貢獻(xiàn)者很容易理解項(xiàng)目是如何運(yùn)行的。

          檢查布爾值

          const?isRaining?=?false
          if(isRaining)?{
          ????console.log('It?is?raining')
          }?else?{
          ????console.log('It?is?not?raining')
          }
          //?It?is?not?raining

          上面的示例中是一種常見(jiàn)的檢查 ?Boolean 值的方法,但是在測(cè)試某些值時(shí)還是出現(xiàn)了錯(cuò)誤。

          在 JavaScript 中,比較 ?0 ?和 ?false ?會(huì)返回 ?true,比較 ?1 ?和 ?true ?會(huì)返回 ?true。這就是說(shuō),如果 ?isRaining ?是 1,那么它就是 ?true。

          這常在對(duì)象中出現(xiàn)錯(cuò)誤,比如:

          const?obj?=?{
          ????name:?'JavaScript',
          ????number:?0
          }
          if(obj.number)?{
          ????console.log('number?property?exists')
          }?else?{
          ????console.log('number?property?does?not?exist')
          }
          //?number?property?does?not?exist

          盡管存在 ?number ?屬性,但 ?obj.number ?返回 ?0,這是一個(gè)假值,因此執(zhí)行了 ?else ?代碼。

          所以,除非你確定了要使用的值的范圍,否則你應(yīng)該測(cè)試布爾值和對(duì)象中的屬性:

          if(a?===?false)...
          if(object.hasOwnProperty(property))...

          使人迷惑的添加和連接

          在 JavaScript 中,加號(hào)(+)有兩種功能:相加和連接。相加是針對(duì)數(shù)字,而連接是針對(duì)字符串。有些開(kāi)發(fā)者經(jīng)常誤用這個(gè)操作符。

          比如:

          const?num1?=?30;
          const?num2?=?"20";
          const?num3?=?30;
          const?word1?=?"Java"
          const?word2?=?"Script"
          console.log(num1?+?num2);
          //?3020
          console.log(num1?+?num3);
          //?60
          console.log(word1?+?word2);
          //?JavaScript

          將字符串和數(shù)字相加時(shí),JavaScript 會(huì)把數(shù)字轉(zhuǎn)換成字符串。而數(shù)字相加時(shí),則進(jìn)行數(shù)學(xué)運(yùn)算。

          總結(jié)

          除了上面羅列出的,肯定還有更多錯(cuò)誤(小錯(cuò)誤或大錯(cuò)誤)。所以,你需要知道最新的語(yǔ)言發(fā)展動(dòng)態(tài)。

          學(xué)習(xí)和避免這些錯(cuò)誤將有助于你構(gòu)建更好、更可靠的 Web 應(yīng)用程序和工具。



          原文鏈接:https://www.freecodecamp.org/news/nine-most-common-mistakes-developers-make-in-javascript/

          作者:Dipto Karmakar

          譯者:Chengjun.L

          掃碼關(guān)注公眾號(hào),訂閱更多精彩內(nèi)容。



          你點(diǎn)的每個(gè)贊,我都認(rèn)真當(dā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>
                  国产一卡二卡三卡免费观看 | 无码操逼动漫 | 天天肏在线 | 大鸡巴狂干小骚比视频 | 99热88 |