如何避免 JavaScript 開發者常犯的 9 個錯誤?

2021-03-02 freeCodeCamp

JavaScript 是一種給網頁添加功能和交互的腳本語言,對於使用不同程式語言的初學者來說很容易理解。有了一些教程,你就可以馬上開始使用它了。

但很多初學者都會犯一些常見的錯誤。在這篇文章中,我們將介紹 9 個常見的錯誤(或者說不好的實踐)以及它們的解決方案,幫助你成為更好的 JavaScript 開發者。

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

正如名稱所示,賦值操作符是用來給變量賦值的。開發者常常把它與相等操作符混淆。

舉個例子:

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

本例中,不是比較 name 變量和  nodejs  字符串,而是為 name 賦值  nodejs,並將  nodejs  輸出到控制臺。

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

對於上述代碼,可以使用以下方法比較值:

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

這兩個比較操作符的區別是:兩個等號執行寬鬆的比較,三個等號執行嚴格的比較。

大致比較時,只比較值。但嚴格地說,值和數據類型都是要比較的。

下面的代碼更好地解釋了這一點:

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

給變量 number 賦值 1。如果將 number 用雙等號與 1 進行比較,會返回 true,因為兩個值都是 1。

然而,在用三個等號的情況下,因為每個值的數據類型不同,所以返回 false。

預期的回調是同步的

在 JavaScript 裡,用回調方法處理異步操作。然而,Promises 和 async/await 是處理異步操作的首選方法,因為多次回調會導致回調地獄。

回調是不同步的。在延遲執行完成操作之後,它們作為一個函數被調用。

例如,全局  setTimeout  接收回調函數作為第一個參數,接收持續時間(毫秒)作為第二個參數:

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 之後,調用回調函數。但是代碼的其餘部分在完成前運行,因此,最後一個 console.log 將首先運行。

開發者經常犯的一個錯誤就是誤解了回調是同步的,比如,認為回調函數一個值用於其他操作。

錯誤在於:

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

由於  secondNumber  不確定,所以輸出  NaN。運行  firstNumber+secondNumber  的時候,仍然沒有定義  secondNumber,因為  setTimeout  函數會在 200ms 之後執行回調。

最好的方法是在回調函數中執行剩餘的代碼:

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

this 指代錯誤

在 JavaScript 中,this 是一個常被誤解的概念。在 JavaScript 使用 this,你需要理解它的作用是什麼,這裡的 this 跟其他語言中的 this 用法不同。

以下是關於 this 的常見錯誤的示例:

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

第一個結果是  JavaScript,因為  this.name  正確地指向對象的 name 屬性。第二個結果是  undefined,因為  this 未指代對象的屬性(包括 name)。

原因在於  this  依賴於正在調用該函數的對象。每個函數都有一個  this  變量,但是它的指向由調用  this  的對象決定。

bj.printName()  的  this直接指向  obj。obj.printNameIn2Secs  的  this  直接指向  obj。然而,但是  this 在回調函數  setTimeout  中沒有指向任何對象,因為沒有任何對象調用它。

如果一個對象調用  setTimeout,則執行obj.setTimeout...。因為沒有對象調用這個函數,所以使用默認對象(即  window)。

window  上沒有  name,故返回  undefined。

在  setTimeout  中保留  this  指代的最好方法是使用  bind、call、apply 或箭頭功能(在 ES6 中引入)。不同於常規函數,箭頭函數不創建自己的  this。

所以,下面的代碼會保留  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

忽視對象的可變性

JavaScript 對象中的引用數據類型不像字符串、數字等原始數據類型。比如,在鍵值對對象中:

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

obj1  和  obj2  在內存中指向相同的地址。

在數組中:

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

開發者經常犯的一個錯誤是忽略了 JavaScript 的這個特性,而這將導致意外的錯誤。

如果出現這種情況,訪問原始屬性的任何嘗試都會返回  undefined  或者引發錯誤。

最好的方法是,當你想複製一個對象的時候,總是創建一個新的引用。為了達到這個目的,擴展運算符(在 ES6 中引入的...)就是一個完美的解決方案。

比如,在鍵值對對象中:

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

在數組中:

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

保存數組和對象至瀏覽器儲存

使用 JavaScript 的時候,開發者可能希望利用  localStorage  來保存值。然而,一個常見的錯誤是直接將數組和對象保存在  localStorage  中。localStorage  只接收字符串。

JavaScript 將對象轉換成字符串以保來保存,其結果是對象保存為  [Object Object],數組保存為逗號分隔開的字符串。

比如:

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

在保存這些對象時,很難訪問它們。例如,對於一個對象,通過  .name  訪問它會導致錯誤。因為  [Object Object]  現在是一個字符串,而不包含  name  屬性。

通過使用  JSON.stringify(將對象轉換為字符串)和  JSON.parse(將字符串轉換為對象),可以更好地保存本地存儲對象和數組。通過這種方式可以輕鬆訪問對象。

上述代碼的正確版本為:

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

不使用默認值

為動態變量設置默認值是一個很好的預防意外錯誤的方法。這裡有一個常見錯誤的例子:

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

由於  a  為  undefined,b 也為  undefined,因此結果為  NaN。你可以使用默認值防止類似錯誤,比如:

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

此外,可以在 ES6 中這樣使用默認值:

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

此示例雖小,但強調了默認值的重要性。

另外,如果沒有提供期望,開發者可以提供一個錯誤或者警告信息。

變量命名錯誤

是的,開發者還是會犯這個錯誤。命名是困難的,但開發人員沒有其他選擇。註解和命名變量一樣,都是編程的好習慣。

比如:

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

變量  discount  沒問題,但是  p  或者  total  呢?是什麼的  total?最好是:

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

對變量進行適當的命名非常重要,因為在特定的時間和將來,可能有別的開發者使用這個代碼庫。

適當地命名變量會讓貢獻者很容易理解項目是如何運行的。

檢查布爾值
const isRaining = false
if(isRaining) {
    console.log('It is raining')
} else {
    console.log('It is not raining')
}
// It is not raining

上面的示例中是一種常見的檢查  Boolean 值的方法,但是在測試某些值時還是出現了錯誤。

在 JavaScript 中,比較  0  和  false  會返回  true,比較  1  和  true  會返回  true。這就是說,如果  isRaining  是 1,那麼它就是  true。

這常在對象中出現錯誤,比如:

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,這是一個假值,因此執行了  else  代碼。

所以,除非你確定了要使用的值的範圍,否則你應該測試布爾值和對象中的屬性:

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

使人迷惑的添加和連接

在 JavaScript 中,加號(+)有兩種功能:相加和連接。相加是針對數字,而連接是針對字符串。有些開發者經常誤用這個操作符。

比如:

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

將字符串和數字相加時,JavaScript 會把數字轉換成字符串。而數字相加時,則進行數學運算。

總結

除了上面羅列出的,肯定還有更多錯誤(小錯誤或大錯誤)。所以,你需要知道最新的語言發展動態。

學習和避免這些錯誤將有助於你構建更好、更可靠的 Web 應用程式和工具。

相關焦點

  • Oracle認證:PHP開發者常犯的MySQL錯誤
    【IT168技術】為了方便廣大考生更好的複習,綜合整理提供了Oracle認證:PHP開發者常犯的MySQL錯誤,以供各位考生考試複習參考,希望對考生複習有所幫助。  PHP開發者常犯的10個MySQL錯誤  資料庫是WEB大多數應用開發的基礎。
  • JavaScript 最容易犯的 10 個錯誤
    為了回饋社區,codeburst 從他們公司的上千個項目中,整理了 JavaScript 出現次數最多的 10 個錯誤。如果能避免這些錯誤的話,那麼你能成為一個更好的程式設計師。以下就是排名最高的 10 個 錯誤:Uncaught TypeError: Cannot read property這個錯誤大家應該經常碰到,當你在 Chrome 瀏覽器中,從一個 undefined 的對象上嘗試讀取一個屬性或者調用一個方法的時候,就會拋出這個錯誤:
  • 來自1000多個項目的十大 JavaScript 錯誤(以及如何避免它們)
    本文由程式設計師新視界原創翻譯原文作者:rollbar英文連結:https://rollbar.com/blog/top-10-javascript-errors/為了回饋我們的開發者社區,我們對比了數千個項目的資料庫,總結了JavaScript中最容易犯的前
  • 開發者必備的Javascript單元測試工具
    【IT168專稿】當前,在軟體開發中單元測試越來越受到開發者的重視,它能提高軟體的開發效率,而且能保障開發的質量。以往,單元測試往往多見於服務端的開發中,但隨著Web編程領域的分工逐漸明細,在前端Javascript開發領域中,也可以進行相關的單元測試,以保障前端開發的質量。
  • 如何避免託福獨立寫作常犯的語法錯誤
    考生常犯的十種語法錯誤   1、主謂不一致   中文不存在主謂一致的問題,因此很多考生在寫英文句子時意識不到這一點。在英語中,主謂一致的問題在一般現在時中出現較多,特別是在第三人稱單數的謂語動詞上容易出現。
  • 來自1000多個項目的十大JavaScript錯誤(以及如何避免)
    為了回饋我們的開發人員社區,我們查看了包含數千個項目的資料庫,並發現了JavaScript中的前10大錯誤。我將向你展示導致它們的原因以及如何防止它們發生。如果你避免這些「陷阱」,它將使你成為更好的開發人員。
  • 10個常犯的期刊投稿合規性錯誤
    這篇文章中,我們將分享十種作者常犯的導致拒稿的期刊合規性錯誤:1.未能遵守期刊指南:這種情況主要是是因為作者在起草稿件時沒有檢查期刊指南,因此也就沒有遵守相應的期刊要求。2.數據不一致:稿件中的數據中有不一致之處,或者是數據的無意義重複。比較常見的是文章正文的數字與表格/圖表中的數字不匹配。
  • 網頁技巧:妥善處理JavaScript中的錯誤
    不管你的技術水平如何,錯誤或異常是應用程式開發者生活的一部分。這樣就避免了與未實例化對象或對不存在的方法調用有關的錯誤。列表A在使用對象(變量和欄位)之前會對它們進行檢查。在使用欄位對象之前,該腳本保證它們為有效或非空欄位。
  • 三歲寶媽經驗分享,教你如何避免母乳餵養常犯的八個錯誤
    導讀:三歲寶媽經驗分享,教你如何避免母乳餵養常犯的八個錯誤各位點開這篇文章的朋友們,想必都是很高的顏值吧,我們真的是很有緣哦,小編每天都會給大家帶來不一樣的育兒資訊,如果對小編的文章或者其他的什麼那麼本期的內容是:三歲寶媽經驗分享,教你如何避免母乳餵養常犯的八個錯誤!那麼我們就來看看吧!之所以將張弟弟兒子的鄰居叫做小龐,是因為這個孩子從小就開始長胖。實際上,他不能被稱為胖子,而應該被稱為強壯。他身上的肉很像瓷器。
  • 管理者在數據分析上常犯的9個錯誤
    你利用AI解決問題的能力很大程度上取決於你如何表述你的問題,以及你是否能建立無歧義的」地面真實「。如果你的標準本身是錯誤的,那麼結果不僅是錯誤的,而且可能對你的業務有害。除非你直接參與定義和監視原始的數據收集目標、工具和策略,否則你可能無法掌握那些能幫你發現錯誤處理、解釋和使用這些數據的關鍵知識。
  • 【第1199期】10 種最常見的 Javascript 錯誤
    今日早讀文章由@elevenbeans 翻譯授權分享正文從這開始~總結於 1000+ 個項目,並闡述如何避免為了回饋我們的開發者社區,我們查看了數千個項目的資料庫,發現了 JavaScript 中頻度最高的 10 種錯誤。我們會告訴你什麼原因導致了這些錯誤,以及如何防止這些錯誤發生。如果你能夠避免落入這些 「陷阱」,你將會成為一個更好的開發者。
  • 數據科學家新手常犯的 13 個錯誤(附工具、學習資源)
    如今越來越多的企業正在變得以數據驅動,世界變得越來越緊密,以致於看起來每個企業都需要數據科學實踐。因此,對數據科學家的需求是巨大的。甚至更好的是,業界數據科學人才短缺已經成為共識。 然而,要成為一名數據科學家並不容易。需要掌握多種技能,才能真正成為一名數據科學家。這些技能包括解決問題、結構化思考、編程和其他專業技能。
  • Python 初學者常犯的5個錯誤,布爾型竟是整型的子類
    在本文中,作者列舉了 5 個初學者常犯的錯誤,希望它們能幫助初學者寫更加正確與優美的代碼。Python 中的預設參數會在執行函數定義時計算一次,這表示在函數完成定義後該表達式只執行一次,因此預設值可以用於後續的每一次調用。如果我們令預設參數為可變的,例如列表或字典等,那麼對於將來所有的調用,該參數都是一直保留且可變的。
  • 乾貨分享:如何規避即興評述的常犯錯誤?
    01. 避免偏題跑題,如果實在覺得沒有切入點,那不妨從自我入手,如果是你面對這樣的問題或事情,會怎麼辦?這實屬下下之策,但是,只要能說出道理來,也能夠贏得主考老師的贊同。 03.
  • 10 種最常見的 Javascript 錯誤
    /為了回饋我們的開發者社區,我們查看了數千個項目的資料庫,發現了 JavaScript 中頻度最高的 10 種錯誤。我們會告訴你什麼原因導致了這些錯誤,以及如何防止這些錯誤發生。如果你能夠避免落入這些 「陷阱」,你將會成為一個更好的開發者。數據才是王道,我們收集並分析了出現頻次排前 10 的 JavaScript 錯誤。 Rollbar 會收集每個項目的所有錯誤,並總結每個錯誤發生的次數。
  • 10大常見JavaScript代碼錯誤淺析,看看你遇到幾個?
    前言如今,javascript是一門非常火的語言,尤其是作為前端開發,你必須對它了如指掌。我們在開發調試的時候,它也經常會報錯,下面我們就來具體看看常見的10個錯誤。Uncaught TypeError: Cannot read property如果你是一名 JavaScript 開發者,對這個錯誤可能已經熟視無睹。在 Chrome 裡讀取未定義對象的屬性或調用未定義對象的方法時就會發生這個錯誤,在 Chrome 開發者控制臺可以很容易地重現這個錯誤。
  • PHP開發者常犯的10個MySQL錯誤
    但是除非你是建立一個非常簡單的資料庫或者只是實驗性的,那麼到大多數時候這個選擇是錯誤的。MyISAM不支持外鍵的約束,這是保證數據完整性的精華所在啊。另外,MyISAM會在添加或者更新數據的時候將整個表鎖住,這在以後的擴展性能上會有很大的問題。解決辦法很簡單:使用InnoDB。
  • 1000+個項目的10大JavaScript錯誤
    讓我們來看一個在現實應用中如何發生這種情況的示例。我們將選擇React,但是不正確初始化的相同原理也適用於Angular,Vue或任何其他框架。TypeError: 『undefined』 is not an object (evaluating這是在Safari中讀取屬性或調用undefined對象上的方法時發生的錯誤,你可以在Safari開發者控制臺中非常輕鬆地進行測試。這基本上與上述針對Chrome的錯誤相同,但Safari使用了不同的錯誤消息。3.
  • 1000+ 個項目的10大JavaScript錯誤
    為了便於閱讀,每個錯誤都被縮短了,讓我們更深入地研究每一個問題,以確定是什麼導致了這些問題,以及如何避免產生這些問題。讓我們來看一個在現實應用中如何發生這種情況的示例。我們將選擇React,但是不正確初始化的相同原理也適用於Angular,Vue或任何其他框架。
  • 人們常犯的24個邏輯錯誤!
    小紅犯了錯誤歸因的謬誤。你操作的感情可能包括恐懼、嫉妒、憐憫、驕傲等等。一個邏輯嚴謹的論述可能激起別人的情感波動,但是如果只用感情操作而不用邏輯論述,那你就犯了訴諸感情的錯誤。每個心智健康的人都會受感情影響,所以這種謬誤很有效,但這也是為什麼這種謬誤是低級和不誠實的手段。例子:小紅在飯店看到小明吃狗肉,於是上前訓斥:「你怎麼可以吃狗肉,小狗多麼可愛,就像小朋友一樣,你忍心傷害小朋友嗎?」