來自1000多個項目的十大 JavaScript 錯誤(以及如何避免它們)

2020-12-12 程式設計師新視界

本文由程式設計師新視界原創翻譯原文作者:rollbar英文連結:https://rollbar.com/blog/top-10-javascript-errors/

為了回饋我們的開發者社區,我們對比了數千個項目的資料庫,總結了JavaScript中最容易犯的前10個錯誤。在這篇文章中,我們將為大家展示導致錯誤發生的原因,以及如何防止錯誤。避免踏入這些「陷阱」可以幫助你成為一個更好的開發者。

因為數據才是王道,所以我們收集、分析並排名了前十位JavaScript錯誤。我們使用Rollbar收集每個項目的所有錯誤,並總結每個錯誤發生的次數。我們通過fingerprints來對錯誤進行分組。基本上,如果第二個錯誤只是第一個錯誤的重複,那麼我們會把兩個錯誤分到一組。這給了用戶一個很好的概覽,而不會像你在日誌文件中看到的超級大型垃圾場那樣雜亂無章。

我們專注於最有可能影響你和用戶的錯誤。為此,我們通過涵蓋不同公司的項目數量來對錯誤進行排位。如果我們只查看每個錯誤發生的總次數,那麼大容量的客戶可能會攜帶著與大多數讀者無關的錯誤壓倒數據集。

以下是前10個JavaScript錯誤:

為了便於閱讀,每個錯誤都縮短了。下面讓我們深入到每一個錯誤以確定錯誤發生的原因,以及應該如何避免。

1.Uncaught TypeError: Cannot read property

如果你是JavaScript開發人員,那麼你可能已經看到過這個錯誤,即便你不願意承認。當你讀取一個屬性或調用一個未定義的對象的方法時,就會在Chrome中發生此錯誤。你可以在Chrome Developer Console中輕鬆地進行測試。

發生這種情況的原因很多,常見的是因為在渲染UI組件時不正確地初始化狀態。讓我們來看一個在真實app中如何發生的例子。我們將選擇React,但不正確初始化的原則也適用於Angular,Vue或任何其他框架。

class Quiz extends Component {componentWillMount() {axios.get('/thedata').then(res => {this.setState({items: res.data});});}render() {return (<ul>{this.state.items.map(item =><li key={item.id}>{item.name}</li>)}</ul>);}}

這裡要意識到兩件重要的事情:

組件的狀態(例如this.state)從undefined開始。當你異步獲取數據時,組件在數據加載之前至少呈現一次,而不管它是在構造函數,componentWillMount還是在componentDidMount中獲取的。當Quiz第一次呈現時,this.state.items是未定義的。這反過來又意味著ItemList將項目定義為未定義,從而導致你在控制臺中得到錯誤——Uncaught TypeError: Cannot read property 『map』 of undefined。這很容易解決。最簡單的方法是:在構造函數中用合理的默認值初始化狀態。

class Quiz extends Component {// Added this:constructor(props) {super(props);// Assign state itself, and a default value for itemsthis.state = {items: []};}componentWillMount() {axios.get('/thedata').then(res => {this.setState({items: res.data});});}render() {return (<ul>{this.state.items.map(item =><li key={item.id}>{item.name}</li>)}</ul>);}}

在具體app中的確切代碼可能有所不同,但我們希望可以給你足夠的線索來修復或避免這個問題。如果這不是你的app中出現的問題,那麼請繼續閱讀,因為我們將在下面涵蓋更多相關錯誤的示例。

2.TypeError: 『undefined』 is not an object (evaluating

這是當你讀取屬性或調用未定義對象上的方法時,在Safari中發生的錯誤。你可以在Safari Developer Console中輕鬆地進行測試。這與在Chrome中發生的上述錯誤基本相同,但Safari使用不同的錯誤消息。

3. TypeError: null is not an object (evaluating

這是當你讀取屬性或調用空對象上的方法時,在Safari中發生的錯誤。你可以在Safari Developer Console中輕鬆地進行測試。

有趣的是,在JavaScript中,null和undefined是不一樣的,這就是為什麼我們看到兩個不同的錯誤信息。未定義通常是一個尚未分配的變量,而null表示該值為空。要驗證它們不相等,請嘗試使用嚴格的相等運算符:

在現實世界的例子中,可能發生此錯誤的一個途徑是在元素被加載之前嘗試在JavaScript中使用DOM元素。這是因為DOM API對於空白的對象引用返回null。

任何執行和處理DOM元素的JS代碼都應在創建DOM元素後執行。JS代碼按照HTML中的布局從上到下進行解釋。所以,如果DOM元素之前有一個標籤,那麼腳本標籤內的JS代碼將在瀏覽器解析HTML頁面時執行。如果在加載腳本之前尚未創建DOM元素,則會出現此錯誤。

在這個例子中,我們可以通過添加事件監聽器來解決這個問題,此監聽器會在頁面準備好的時候通知我們。一旦addEventListener被觸發,init()方法就可以使用DOM元素。

<script>function init() {var myButton = document.getElementById("myButton");var myTextfield = document.getElementById("myTextfield");myButton.onclick = function() {var userName = myTextfield.value;}}document.addEventListener('readystatechange', function() {if (document.readyState === "complete") {init();}});</script><form><input type="text" id="myTextfield" placeholder="Type your name" /><input type="button" id="myButton" value="Go" /></form>

4.(unknown): Script error

當未捕獲的JavaScript錯誤違背跨同源策略而跨越域邊界時,會發生Script error。例如,如果你將你的JavaScript代碼託管在CDN上,則任何未捕獲的錯誤(通過window.onerror處理程序引發而不是在try-catch中捕獲的錯誤)都將被報告為「Script error」,而不包含有用信息。這是一種瀏覽器安全措施,旨在防止跨域傳遞數據,否則將不允許進行通信。

要獲得真正的錯誤消息,請執行以下操作:

1.發送Access-Control-Allow-Origin標頭

將Access-Control-Allow-Origin標頭設置為* 表示可以從任何域正確訪問資源。如有必要,你可以將* 替換為你的域:例如,Access-Control-Allow-Origin: www.example.com。但是,處理多個域會變得棘手,並且如果由於可能出現的緩存問題而使用CDN,那或許就不值得你付出努力。更多信息請點這裡。

下面是一些關於如何在各種環境中設置這個標頭的例子:

Apache

在JavaScript文件所在的文件夾中,使用以下內容創建一個.htaccess文件:

Header add Access-Control-Allow-Origin "*"

Nginx

將add_header指令添加到提供JavaScript文件的位置塊中:

location ~ ^/assets/ {add_header Access-Control-Allow-Origin *;}

HAProxy

將以下內容添加到提供JavaScript文件的東西的後端:

rspadd Access-Control-Allow-Origin:\ *

2.在腳本標籤上設置crossorigin =「anonymous」

在HTML原始碼中,對於設置了Access-Control-Allow-Origin標頭的每個腳本,在SCRIPT標籤上設置crossorigin="anonymous"。在腳本標籤中添加crossorigin屬性之前,請確保已驗證正在為腳本文件發送標頭。在Firefox中,如果存在crossorigin屬性,但Access-Control-Allow-Origin標頭不存在,則將不執行腳本。

5. TypeError: Object doesn’t support property

這是在調用未定義的方法時發生在IE中的錯誤。你可以在IE Developer Console中進行測試。

這相當於Chrome中的「TypeError: 『undefined』 is not a function」錯誤。是的,不同的瀏覽器對相同的邏輯錯誤具有不同的錯誤消息。

對於使用JavaScript命名空間的Web應用程式中的IE,這是一個常見的問題。在這種情況下,99.9%的問題是IE無法將當前名稱空間內的方法綁定到this關鍵字。例如,如果你有JS命名空間Rollbar和方法isAwesome。通常,如果你在Rollbar命名空間內,則可以使用以下語法調用isAwesome方法:

this.isAwesome();

Chrome、Firefox和Opera會高興地接受這個語法。但是,IE則不會。因此,使用JS命名空間時最安全的選擇是始終以實際名稱空間作為前綴。

Rollbar.isAwesome();

6. TypeError: 『undefined』 is not a function

當你調用未定義的函數時,在Chrome中就會發生此錯誤。你可以在Chrome Developer Console和Mozilla Firefox Developer Console中進行測試。

隨著JavaScript編碼技術和設計模式在過去幾年中變得越來越複雜,在回調和關閉中自引用範圍的擴散也相應增加,從而使得這種混亂成為一個相當普遍的來源。

考慮下面的代碼片段:

function testFunction() {this.clearLocalStorage();this.timer = setTimeout(function() {this.clearBoard(); // what is "this"?}, 0);};

執行上述代碼將會導致以下錯誤:「Uncaught TypeError: undefined is not a function」。得到上述錯誤的原因是,當你調用setTimeout()時,實際上是調用window.setTimeout()。因此,在窗口對象的上下文中定義了一個正被傳遞給setTimeout()的匿名函數,該函數沒有clearBoard()方法。

一個傳統的,與舊瀏覽器兼容的解決方案是在一個變量中簡單地將引用保存到this,然後可以由閉包繼承。例如:

function testFunction () {this.clearLocalStorage();var self = this; // save reference to 'this', while it's still this!this.timer = setTimeout(function(){self.clearBoard();}, 0);};

或者,在較新的瀏覽器中,你可以使用bind()方法傳遞合理的引用:

function testFunction () {this.clearLocalStorage();this.timer = setTimeout(this.reset.bind(this), 0); // bind to 'this'};function testFunction(){this.clearBoard(); //back in the context of the right 'this'!};

7.Uncaught RangeError: Maximum call stack

這是發生在Chrome中的錯誤。導致錯誤發生的其中一種情況是調用一個不終止的遞歸函數。你可以在Chrome Developer Console中進行測試。

如果你將值傳遞給超出範圍的函數,也可能發生這種情況。許多函數對於輸入值只接受特定範圍的數字。例如,Number.toExponential(digits)和Number.toFixed(digits)接受從0到20的數字,Number.toPrecision(digits)接受從1到21的數字。

var a = new Array(4294967295); //OKvar b = new Array(-1); //range errorvar num = 2.555555;document.writeln(num.toExponential(4)); //OKdocument.writeln(num.toExponential(-2)); //range error!num = 2.9999;document.writeln(num.toFixed(2)); //OKdocument.writeln(num.toFixed(25)); //range error!num = 2.3456;document.writeln(num.toPrecision(1)); //OKdocument.writeln(num.toPrecision(22)); //range error!

8. TypeError: Cannot read property 『length』

這是Chrome中發生的錯誤,原因是因為讀取未定義變量的長度屬性。你可以在Chrome Developer Console中進行測試。

你通常會在數組上找到定義的長度,但是如果數組未初始化或者變量名稱隱藏在另一個上下文中,則可能會遇到此錯誤。讓我們通過下面的例子來理解這個錯誤。

var testArray= ["Test"];function testFunction(testArray) {for (var i = 0; i < testArray.length; i++) {console.log(testArray[i]);}}testFunction();

當你用參數聲明一個函數時,這些參數會變成本地參數。這意味著即使你有名稱為testArray的變量,函數中具有相同名稱的參數將也被視為是本地的。

有兩種方法可以解決你的問題:

1)刪除函數聲明語句中的參數(事實證明,你想訪問那些聲明在函數之外的變量,所以你不需要函數的參數):

var testArray = ["Test"];/* Precondition: defined testArray outside of a function */function testFunction(/* No params */) {for (var i = 0; i < testArray.length; i++) {console.log(testArray[i]);}}testFunction();

2)調用傳遞給我們聲明的數組的函數:

var testArray = ["Test"];function testFunction(testArray) {for (var i = 0; i < testArray.length; i++) {console.log(testArray[i]);}}testFunction(testArray);

9.Uncaught TypeError: Cannot set property

當我們嘗試訪問一個未定義的變量時,它總是返回undefined,我們不能獲取或設置任何undefined的屬性。在這種情況下,應用程式將拋出「Uncaught TypeError cannot set property of undefined」。

例如,在Chrome瀏覽器中:

Uncaught TypeError屏幕截圖:無法設置屬性

如果test對象不存在,將拋出「Uncaught TypeError cannot set property of undefined」錯誤。

10. ReferenceError: event is not defined

當你嘗試訪問未定義的變量或超出當前範圍的變量時,會引發此錯誤。你可以在Chrome瀏覽器中輕鬆地進行測試。

如果你在使用事件處理系統時遇到此錯誤,那麼請確保使用傳入的事件對象作為參數。像IE這樣的老瀏覽器提供了一個全局變量事件,但並不是所有瀏覽器都支持。例如jQuery這樣的庫採取的是試圖規範化這種行為。儘管如此,最好的做法是使用傳入到事件處理函數的對象。

function myFunction(event) {event = event.which || event.keyCode;if(event.keyCode===13){alert(event.keyCode);}}

結論

我們希望你可以從這篇文章中學到新的東西,幫助避免錯誤,或者希望本指南幫助解決了令你頭痛的問題。儘管如此,即使有最佳實踐做法,生產中也依然會出現意想不到的錯誤。查看影響用戶的錯誤,並擁有快速解決問題的好工具,這一點非常重要。

相關焦點

  • 來自1000多個項目的十大JavaScript錯誤(以及如何避免)
    為了回饋我們的開發人員社區,我們查看了包含數千個項目的資料庫,並發現了JavaScript中的前10大錯誤。我將向你展示導致它們的原因以及如何防止它們發生。如果你避免這些「陷阱」,它將使你成為更好的開發人員。
  • 如何避免 JavaScript 開發者常犯的 9 個錯誤?
    但很多初學者都會犯一些常見的錯誤。在這篇文章中,我們將介紹 9 個常見的錯誤(或者說不好的實踐)以及它們的解決方案,幫助你成為更好的 JavaScript 開發者。將賦值操作符(=)和相等操作符(==,===)混為一談正如名稱所示,賦值操作符是用來給變量賦值的。
  • 網頁技巧:妥善處理JavaScript中的錯誤
    不管你的技術水平如何,錯誤或異常是應用程式開發者生活的一部分。Web開發的不連貫性留下了許多錯誤能夠發生並確實已經發生的地方。解決的關鍵在於處理任何不可預見的(或可預見的錯誤),來控制用戶的體驗。利用JavaScript,就有多種技術和語言特色可以用來正確地解決任何問題。事事檢查在開始之前檢查一切是一個好的編程習慣,也就是說,你應該在利用它們之前,檢查對象、方法調用等的有效性。
  • CRM:6個常見的銷售代表錯誤以及如何避免它們
    我們看一下銷售人員常犯的一些常見錯誤以及如何防止它們。常見的銷售代表錯誤以及如何預防有人會說銷售是藝術品因此,讓我們看一下銷售人員最常犯的錯誤,以及如何防止他們混淆錯誤的要素。例如,如果你要銷售CRM解決方案,請不要說明其工作原理的技術性,而要談談它如何升級他們的銷售流程並增加收入。如果你認為降低產品價格會吸引更多客戶,那你可能是錯的;如果你對產品定價過低,則對客戶的心理影響就是他們會將其視為低價值產品。提供折扣和特別促銷活動只會給您短期的銷售增長,因為一旦討價還價的人滿意,它們就會恢復正常。
  • 1000+ 個項目的10大JavaScript錯誤
    為了便於閱讀,每個錯誤都被縮短了,讓我們更深入地研究每一個問題,以確定是什麼導致了這些問題,以及如何避免產生這些問題。讓我們來看一個在現實應用中如何發生這種情況的示例。我們將選擇React,但是不正確初始化的相同原理也適用於Angular,Vue或任何其他框架。
  • 解決JavaScript錯誤從未如此簡單!
    檢測,診斷和銷毀影響客戶的JavaScript錯誤。藉助Raygun提供的智能JavaScript錯誤跟蹤軟體,您可以提醒您影響用戶的問題,第二個問題發生。JavaScript錯誤往往會很嘈雜,並引發大量無用的信息。Raygun可以幫助您消除這些噪音,並專注於影響應用程式用戶數量最多的問題。
  • 1000+個項目的10大JavaScript錯誤
    讓我們來看一個在現實應用中如何發生這種情況的示例。我們將選擇React,但是不正確初始化的相同原理也適用於Angular,Vue或任何其他框架。; <li key={item.id}>{item.name}</li> )} </ul> ); }}你的應用程式中的實際代碼可能會有不同,但我希望已經給了你足夠的線索,讓你在你的應用程式中修復或避免這個問題
  • 【第1199期】10 種最常見的 Javascript 錯誤
    今日早讀文章由@elevenbeans 翻譯授權分享正文從這開始~總結於 1000+ 個項目,並闡述如何避免為了回饋我們的開發者社區,我們查看了數千個項目的資料庫,發現了 JavaScript 中頻度最高的 10 種錯誤。我們會告訴你什麼原因導致了這些錯誤,以及如何防止這些錯誤發生。如果你能夠避免落入這些 「陷阱」,你將會成為一個更好的開發者。
  • 10 種最常見的 Javascript 錯誤
    /為了回饋我們的開發者社區,我們查看了數千個項目的資料庫,發現了 JavaScript 中頻度最高的 10 種錯誤。我們會告訴你什麼原因導致了這些錯誤,以及如何防止這些錯誤發生。如果你能夠避免落入這些 「陷阱」,你將會成為一個更好的開發者。數據才是王道,我們收集並分析了出現頻次排前 10 的 JavaScript 錯誤。 Rollbar 會收集每個項目的所有錯誤,並總結每個錯誤發生的次數。
  • JavaScript錯誤處理完全指南
    在代碼中,你將主要使用 Error 和 TypeError 這兩種最常見的類型來創建自己的錯誤對象。一般來說,大多數錯誤將直接來自 JavaScript 引擎,例如 InternalError 或 SyntaxError。
  • JavaScript 基礎語法
    之前學堂的小編-利利給大家分享了如何才能把JavaScript學好的文章,該文章內容涉及了JavaScript的基本知識以及JavaScript學習方法。如果想了解具體的JavaScript基礎知識,可以回復「學JS」到「HTML5學堂」公眾號。
  • 6個減少JavaScript錯誤噪音的技巧
    通過Web開發人員提供的這六個重要提示,了解如何減少JavaScript錯誤噪音並找到JavaScript zen。請繼續閱讀!如果您嘗試使用JavaScript錯誤跟蹤來構建和迭代您的應用,那麼您可能會遇到一個常見的問題:嘈雜,低價值的通知,這使得很難識別出高優先級的問題。
  • javascript之常用數據類型及判斷方法
    ,今天,我們來具體重新了解下javascript中的常見數據類型以及他們的判斷方法。javascript數據類型分類一.根據數據類型的複雜方式劃分數據分類在javascipt中數據的複雜方式一般分為:基本類型,特殊類型以及複雜類型
  • UX設計師總結:6個避免可用性錯誤的建議
    在這篇文章中,你可以了解更多關於:用戶體驗設計師在不斷變化項目中的經驗一個不太為人所知的可用性錯誤的觀點改進工作流程的6個提示,以避免可用性錯誤和網站轉換率低的問題幾個月前,我在設計一家在線商店時正在閱讀如何避免可用性錯誤
  • JavaScript中使用bind()方法讓代碼更乾淨
    來自:碼農網連結:http://www.codeceo.com/article/
  • 12 個 GitHub 上超火的 JavaScript 奇技淫巧項目,找到寫 JavaScript 的靈感!
    公眾號:前端GitHub,專注於挖掘 GitHub 上優秀的前端開源項目,並以專題的形式推薦,每專題大概 10 個好項目,每周會有一到三篇精華文章推送。已經推薦了 面試項目、css奇技淫巧項目、代碼規範項目、數據結構與算法項目、管理後臺模板、前端必備在線工具 等專題的近 100 個優秀項目了。
  • javascript成神之路(1):如何編寫高質量的js代碼
    原型以及原型鏈一、如何書寫可維護性的代碼當出現bug的時候如果你能立馬修復它是最好的,此時解決問題的四路在你腦中還是很清晰的。若瀏覽器不支持JSON.parse(),你可 以使用來自JSON.org的庫。同樣重要的是要記住,給setInterval(), setTimeout()和Function()構造函數傳遞字符串,大部分情況下,與使用eval()是類似的,因此要避免。
  • 如何正確合理使用 JavaScript async/await
    然而,它們也存在一些坑及問題。在本文中,將從不同的角度探討 async/await,並演示如何正確有效地使用這對兄弟。async 作用是什麼從 MDN 可以看出:async 函數返回的是一個 Promise 對象。
  • 走近 (javascript, 函數式)
    函數式編程卻屬於聲明式的編程方式,這種範式會描述一系列的操作,而不去暴露它們是如何實現的,以及數據是如何從中間穿過。在這裡,「動詞」是第一詞彙,我們更加注重於描述不同動作之間的組合和順序。比如,我們需要將一個數組的每個數平方以後,找出其中的奇數,並生成新的數組。
  • javascript如何執行調試
    javascript中執行調試的方法有:使用console.log()方法,或者使用關鍵字「debugger」。有時代碼可能會包含某些錯誤。而作為腳本語言,JavaScript無法在瀏覽器中顯示任何錯誤消息。但是,這些錯誤卻會影響輸出。