中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中常見的BUG及其修復方法分享

發布時間:2021-08-12 17:17:35 來源:億速云 閱讀:272 作者:chen 欄目:編程語言

這篇文章主要講解了“JavaScript中常見的BUG及其修復方法分享”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JavaScript中常見的BUG及其修復方法分享”吧!

如今網站幾乎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的引用正確

};

 還有一些JavaScript中錯誤的正確處理方式,歡迎點擊參考閱讀l。

2. 和塊作用域(block scope)有關的BUG

在大多數程序語言中,每一個函數塊都有一個獨立的新的作用域,但是在JavaScript中并不是。例如:


for (var i = 0; i < 10; i++) {

/* ... */

}

console.log(i); // 會輸出什么呢?

通常在這種情況下,調用console.log()會輸出undefined或則報錯。不過呢,這里會輸出10。在JavaScript中,即使for循環已經結束,變量i依然存在,并且記錄最后的值。有些開發者會忘記這一點,然后導致許多bug。我們可以使用let而不是for來杜絕這一問題。

3. 內存泄漏

你需要監控內存使用量,因為泄露很難避免。內存泄露可能由于引用不存在的對象或則循環引用導致。

  • 如何避免:關注對象的可訪問性(reachability)。

  • 可訪問的對象:

    • 現有的call stack任何位置可以訪問的對象

    • 全局對象

當一個對象可以通過引用訪問到,那么會在內存中保存。瀏覽器的垃圾回收器僅僅會把那些不可訪問的對象回收。

4. 混淆的相等判斷

JavaScript自動將所有在布爾環境下的變量類型轉換為布爾類型,但是可能導致bug。舉例:


// 所有都是true

console.log(false == '0');

console.log(null == undefined);

console.log(" \t\r\n" == 0);

console.log('' == 0);

 

// 注意:下面兩個也是

if ({}) // …

if ([]) // …

{}和[]都是對象,他們都會被轉換為true。為了防止bug出現,推薦使用===和!==來做比較,因為不會隱式做類型轉換。

5. 低效的DOM操作

在JavaScript中,你可以輕松操作DOM(添加、修改和刪除),但是開發者往往很低效地去操作。這會導致bug出現,因為這些操作非常耗費計算資源。為了解決這個問題,推薦使用文檔碎片(Document Fragment),如果你需要操作多個DOM元素。

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會自動拋出錯誤

感謝各位的閱讀,以上就是“JavaScript中常見的BUG及其修復方法分享”的內容了,經過本文的學習后,相信大家對JavaScript中常見的BUG及其修復方法分享這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

都昌县| 东乌珠穆沁旗| 水城县| 六盘水市| 武陟县| 义马市| 浦北县| 巴马| 通渭县| 登封市| 山阳县| 沁阳市| 万荣县| 耒阳市| 平山县| 年辖:市辖区| 南木林县| 铜陵市| 黔东| 鸡东县| 五华县| 新乐市| 灌云县| 庆元县| 信阳市| 灵川县| 霍邱县| 陇川县| 朝阳市| 乌拉特中旗| 磐安县| 昌邑市| 信丰县| 化德县| 卢龙县| 兴宁市| 利津县| 济宁市| 全椒县| 平利县| 东山县|