摘要:在中傳入的匿名函數是在這個對象環境下,所以是指向,但是并沒有方法。自從年雙十一正式上線,累計處理了億錯誤事件,得到了金山軟件等眾多知名用戶的認可。
譯者按: JavaScript語言設計太靈活,用起來不免要多加小心掉進坑里面。
原文: Top 10 bugs and their bug fixing
譯者: Fundebug
為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用于學習。
如今網站幾乎100%使用JavaScript。JavaScript看上去是一門十分簡單的語言,然而事實并不如此。它有很多容易被弄錯的細節,一不注意就導致BUG。
1. 錯誤的對this進行引用在閉包或則回調中,this關鍵字的作用域很容易弄錯。舉個例子:
Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(function() { this.clearBoard(); // 此處this指的是? }, 0); };
如果執行上面的代碼,我們會看到報錯:
Uncaught TypeError: undefined is not a function
出錯的原因在于:當你調用setTimeout函數,你實際上調用的是window.setTimeout()。在setTimeout中傳入的匿名函數是在window這個對象環境下,所以this是指向window,但是window并沒有clearBoard方法。
如何解決呢?定義新的變量引用指向Game對象的this,然后就可以使用啦。
Game.prototype.restart = function () { this.clearLocalStorage(); var self = this; // 將this指向的對象綁定到self this.timer = setTimeout(function(){ self.clearBoard(); }, 0); };
或則使用bind()函數:
Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(this.reset.bind(this), 0); // bind to "this" }; Game.prototype.reset = function(){ this.clearBoard(); // 此處this的引用正確 };2. 和塊作用域(block scope)有關的BUG
在大多數程序語言中,每一個函數塊都有一個獨立的新的作用域,但是在JavaScript中并不是。例如:
for (var i = 0; i < 10; i++) { /* ... */ } console.log(i); // 會輸出什么呢?
通常在這種情況下,調用console.log()會輸出undefined或則報錯。不過呢,這里會輸出10。在JavaScript中,即使for循環已經結束,變量i依然存在,并且記錄最后的值。有些開發者會忘記這一點,然后導致許多bug。我們可以使用let而不是var來杜絕這一問題。
3. 內存泄漏你需要監控內存使用量,因為泄露很難避免。內存泄露可能由于引用不存在的對象或則循環引用導致。
如何避免:關注對象的可訪問性(reachability)。
可訪問的對象:
現有的call stack任何位置可以訪問的對象
全局對象
當一個對象可以通過引用訪問到,那么會在內存中保存。瀏覽器的垃圾回收器僅僅會把那些不可訪問的對象回收。
4. 混淆的相等判斷JavaScript自動將所有在布爾環境下的變量類型轉換為布爾類型,但是可能導致bug。舉例:
// 所有都是true console.log(false == "0"); console.log(null == undefined); console.log(" " == 0); console.log("" == 0); // 注意:下面兩個也是 if ({}) // … if ([]) // …
{}和[]都是對象,他們都會被轉換為true。為了防止bug出現,推薦使用===和!==來做比較,因為不會隱式做類型轉換。
5. 低效的DOM操作在JavaScript中,你可以輕松操作DOM(添加、修改和刪除),但是開發者往往很低效地去操作。這會導致bug出現,因為這些操作非常耗費計算資源。為了解決這個問題,推薦使用文檔碎片(Document Fragment),如果你需要操作多個DOM元素。
廣告: 你的線上代碼真的沒有BUG嗎?歡迎免費使用Fundebug!我們可以幫助您第一時間發現BUG!
6. 在for循環中錯誤的定義函數舉例:
var elements = document.getElementsByTagName("input"); var n = elements.length; // 假設我們有10個元素 for (var i = 0; i < n; i++) { elements[i].onclick = function() { console.log("元素編號#" + i); }; }
如果我們有10個元素,那么點擊任何一個元素都會顯示“元素編號#10”!因為在onclick被調用的時候,for循環已經結束,因此所有的i都是10。
解法:
var elements = document.getElementsByTagName("input"); var n = elements.length; // 假設有10個元素 var makeHandler = function(num) { // outer function return function() { // inner function console.log("元素編號##" + num); }; }; for (var i = 0; i < n; i++) { elements[i].onclick = makeHandler(i+1); }
makeHandler在for循環執行的時候立即被調用,獲取到當前的值i+1,并且存儲在變量num中。makeHandler返回一個函數使用num變量,該函數被綁定到元素的點擊事件。
7. 通過原型錯誤地繼承開發者如果沒能正確理解繼承的原理,那么就可能寫出有bug的代碼:
BaseObject = function(name) { if(typeof name !== "undefined") { this.name = name; } else { this.name = "default" } }; var firstObj = new BaseObject(); var secondObj = new BaseObject("unique"); console.log(firstObj.name); // -> 輸出"default" console.log(secondObj.name); // -> 輸出"unique"
但是,如果我們做如下操作:
delete secondObj.name;
那么:
console.log(secondObj.name); // -> 輸出"undefined"
而我們實際上想要的結果是打印默認的name。
BaseObject = function (name) { if(typeof name !== "undefined") { this.name = name; } }; BaseObject.prototype.name = "default";
每一個BaseObject都繼承name屬性,并且默認值為default。此時如果secondObj的name屬性被刪除掉,通過原型鏈查找會返回正確的默認值。
var thirdObj = new BaseObject("unique"); console.log(thirdObj.name); // -> 輸出"unique" delete thirdObj.name; console.log(thirdObj.name); // -> 輸出"default"8. 實例方法中的無效引用
我們來實現一個簡單的構造函數用來創建對象:
var MyObject = function() {} MyObject.prototype.whoAmI = function() { console.log(this === window ? "window" : "MyObj"); }; var obj = new MyObject();
為了使用方便,我們定義變量whoAmI來引用obj.whoAmI:
var whoAmI = obj.whoAmI;
打印出來看看:
console.log(whoAmI);
控制臺會輸出:
function () { console.log(this === window ? "window" : "MyObj"); }
現在我們來對比一下兩者調用的區別:
obj.whoAmI(); // 輸出"MyObj" (和期望一致) whoAmI(); // 輸出"window" (竟然輸出了window)
當我們把obj.whoAmI賦值給whoAmI的時候,這個新的變量whoAmI是定義在全局下,因此this指向全局的window,而不是MyObj。如果我們真的要獲取對MyObj的函數的引用,需要在其作用域下。
var MyObject = function() {} MyObject.prototype.whoAmI = function() { console.log(this === window ? "window" : "MyObj"); }; var obj = new MyObject(); obj.w = obj.whoAmI; // 任然在obj的作用域 obj.whoAmI(); // 輸出"MyObj" obj.w(); // 輸出"MyObj"9. setTimeout/setInterval函數第一個參數誤用字符串
如果你將一個字符串作為setTimeout/setTimeInterval,它會被傳給函數構造函數并構建一個新的函數。該操作流程很慢而且低效,并導致bug出現。
var hello = function(){ console.log("hello, fundebug !"); } setTimeout("hello", 1000);
一個好的替代方法就是傳入函數作為參數:
setInterval(logTime, 1000); // 將logTime函數傳入 setTimeout(function() { // 傳入一個匿名函數 logMessage(msgValue); }, 1000);10. 未能成功使用strict mode
使用strict model會增加很多限制條件來加強安全和防止某些錯誤的出現,如果不使用strict mode,你就相當于少了一個得力的助手幫你避免錯誤:
更加容易debug
避免不小心定義了不該定義的全局變量
避免this隱式轉換
避免屬性名字或則參數值的重復使用
eval()更加安全
無效地使用delete會自動拋出錯誤
關于FundebugFundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了6億+錯誤事件,得到了Google、360、金山軟件等眾多知名用戶的認可。歡迎免費試用!
版權聲明轉載時請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/11/15/top_10_bugs_and_fixing_method/
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/90201.html
摘要:表示錯誤沒有被語句捕獲,是錯誤的名字。如何修復錯誤確保方法名正確。這個錯誤的行號將指出正確的位置。相關錯誤代碼調用的方法在當前狀態無法調用。通常由引起,在方法準備完畢之前調用它會引起錯誤。原文翻譯出處涂鴉碼農錯誤以及如何修復 (看到一篇調試JS很有用的文章,收藏一下) JavaScript 調試是一場噩夢:首先給出的錯誤非常難以理解,其次給出的行號不總有幫助。有個查找錯誤含義,及修復...
摘要:圖對可復用代碼挑戰最大的五項問題五大開發問題如下。瀏覽器的缺陷修復。瀏覽器缺失的功能。復雜的地方是,當前瀏覽器會在未來的瀏覽器版本中被修復。假設瀏覽器引起常見的網站問題為解決瀏覽器使用特殊技巧,將來瀏覽器發布新版本修復了,就會出現問題。 任意一段重要的代碼都需要關注無數的開發問題。但是,其中對可復用JavaScript代碼挑戰最大的五項問題如圖14.2所示。 showImg(https...
目錄 1.為什要遵守代碼規范 2.編寫代碼需遵守的幾個原則 3.編碼規范(Coding Conventions) 4.命名規范(Naming Conventions) 5.css基礎class類 1.為什要遵守代碼規范 軟件bug的修復是昂貴的,并且隨著時間的推移,這些bug的成本也會增加,尤其當這些bug潛伏并慢慢出現在已經發布的軟件中時。當你發現bug 的時候就立即修復它是最好的,此時你代...
摘要:前端異常監控插件更新至,修復了個小修復用戶行為中重復記錄請求的修復的為報錯的這個都不會影響功能,不過為了避免造成困擾,請大家及時更新插件。 摘要: 修復2個BUG,請大家及時更新。 showImg(https://segmentfault.com/img/remote/1460000019373421?w=900&h=383); Fundebug前端異常監控服務 Fundebug是專業...
閱讀 1065·2021-11-24 09:39
閱讀 3602·2021-11-22 13:54
閱讀 2560·2021-10-11 10:59
閱讀 800·2021-09-02 15:40
閱讀 1036·2019-08-30 15:55
閱讀 1056·2019-08-30 13:57
閱讀 2315·2019-08-30 13:17
閱讀 3035·2019-08-29 18:32