溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Web前端中JavaScript常見BUG及修復(fù)方法是怎樣的

發(fā)布時(shí)間:2021-09-30 09:42:27 來源:億速云 閱讀:141 作者:柒染 欄目:編程語言

這篇文章給大家介紹Web前端中JavaScript常見BUG及修復(fù)方法是怎樣的,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

JavaScript看上去是一門十分簡(jiǎn)單的語言,然而事實(shí)并不如此。它有很多容易被弄錯(cuò)的細(xì)節(jié),一不注意就導(dǎo)致BUG。

一、錯(cuò)誤的對(duì)this進(jìn)行引用

在閉包或則回調(diào)中,this關(guān)鍵字的作用域很容易弄錯(cuò)。舉個(gè)例子:

Game.prototype.restart = function () {

this.clearLocalStorage();

this.timer = setTimeout(function() {

this.clearBoard(); // 此處this指的是?

}, 0);

};

如果執(zhí)行上面的代碼,我們會(huì)看到報(bào)錯(cuò):

Uncaught TypeError: undefined is not a function

出錯(cuò)的原因在于:當(dāng)你調(diào)用setTimeout函數(shù),你實(shí)際上調(diào)用的是window.setTimeout()。在setTimeout中傳入的匿名函數(shù)是在window這個(gè)對(duì)象環(huán)境下,所以this是指向window,但是window并沒有clearBoard方法。

如何解決呢?定義新的變量引用指向Game對(duì)象的this,然后就可以使用啦。

Game.prototype.restart = function () {

this.clearLocalStorage();

var self = this; // 將this指向的對(duì)象綁定到self

this.timer = setTimeout(function(){

self.clearBoard();

}, 0);

};

或則使用bind()函數(shù):

Game.prototype.restart = function () {

this.clearLocalStorage();

this.timer = setTimeout(this.reset.bind(this), 0); // bind to 'this'

};

Game.prototype.reset = function(){

this.clearBoard(); // 此處this的引用正確

};

二、和塊作用域(block scope)有關(guān)的BUG

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

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

/* ... */

}

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

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

三、內(nèi)存泄漏

你需要監(jiān)控內(nèi)存使用量,因?yàn)樾孤逗茈y避免。內(nèi)存泄露可能由于引用不存在的對(duì)象或則循環(huán)引用導(dǎo)致。

· 如何避免:關(guān)注對(duì)象的可訪問性(reachability)。

· 可訪問的對(duì)象:

§ 現(xiàn)有的call stack任何位置可以訪問的對(duì)象

§ 全局對(duì)象

當(dāng)一個(gè)對(duì)象可以通過引用訪問到,那么會(huì)在內(nèi)存中保存。瀏覽器的垃圾回收器僅僅會(huì)把那些不可訪問的對(duì)象回收。

四、混淆的相等判斷

JavaScript自動(dòng)將所有在布爾環(huán)境下的變量類型轉(zhuǎn)換為布爾類型,但是可能導(dǎo)致bug。舉例:

// 所有都是true

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

console.log(null == undefined);

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

console.log('' == 0);

// 注意:下面兩個(gè)也是

if ({}) // …

if ([]) // …

{}和[]都是對(duì)象,他們都會(huì)被轉(zhuǎn)換為true。為了防止bug出現(xiàn),推薦使用===和!==來做比較,因?yàn)椴粫?huì)隱式做類型轉(zhuǎn)換。

五、低效的DOM操作

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

六、在for循環(huán)中錯(cuò)誤的定義函數(shù)

舉例:

var elements = document.getElementsByTagName('input');

var n = elements.length; // 假設(shè)我們有10個(gè)元素

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

elements[i].onclick = function() {

console.log("元素編號(hào)#" + i);

};

}

如果我們有10個(gè)元素,那么點(diǎn)擊任何一個(gè)元素都會(huì)顯示“元素編號(hào)#10”!因?yàn)樵趏nclick被調(diào)用的時(shí)候,for循環(huán)已經(jīng)結(jié)束,因此所有的i都是10。

解法:

var elements = document.getElementsByTagName('input');

var n = elements.length; // 假設(shè)有10個(gè)元素

var makeHandler = function(num) { // outer function

return function() { // inner function

console.log("元素編號(hào)##" + num);

};

};

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

elements[i].onclick = makeHandler(i+1);

}

makeHandler在for循環(huán)執(zhí)行的時(shí)候立即被調(diào)用,獲取到當(dāng)前的值i+1,并且存儲(chǔ)在變量num中。makeHandler返回一個(gè)函數(shù)使用num變量,該函數(shù)被綁定到元素的點(diǎn)擊事件。

七、通過原型錯(cuò)誤地繼承

開發(fā)者如果沒能正確理解繼承的原理,那么就可能寫出有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'

而我們實(shí)際上想要的結(jié)果是打印默認(rèn)的name。

BaseObject = function (name) {

if(typeof name !== "undefined") {

this.name = name;

}

};

BaseObject.prototype.name = 'default';

每一個(gè)BaseObject都繼承name屬性,并且默認(rèn)值為default。此時(shí)如果secondObj的name屬性被刪除掉,通過原型鏈查找會(huì)返回正確的默認(rèn)值。

var thirdObj = new BaseObject('unique');

console.log(thirdObj.name); // -> 輸出'unique'

delete thirdObj.name;

console.log(thirdObj.name); // -> 輸出'default'

八、實(shí)例方法中的無效引用

我們來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的構(gòu)造函數(shù)用來創(chuàng)建對(duì)象:

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);

控制臺(tái)會(huì)輸出:

function () {

console.log(this === window ? "window" : "MyObj");

}

現(xiàn)在我們來對(duì)比一下兩者調(diào)用的區(qū)別:

obj.whoAmI(); // 輸出"MyObj" (和期望一致)

whoAmI(); // 輸出"window" (竟然輸出了window)

當(dāng)我們把obj.whoAmI賦值給whoAmI的時(shí)候,這個(gè)新的變量whoAmI是定義在全局下,因此this指向全局的window,而不是MyObj。如果我們真的要獲取對(duì)MyObj的函數(shù)的引用,需要在其作用域下。

var MyObject = function() {}

MyObject.prototype.whoAmI = function() {

console.log(this === window ? "window" : "MyObj");

};

var obj = new MyObject();

obj.w = obj.whoAmI; // 任然在obj的作用域?qū)幉锌漆t(yī)院http://www.jzspfk.com/

obj.whoAmI(); // 輸出"MyObj"

obj.w(); // 輸出"MyObj"

九、settimeout/setlnterval函數(shù)第一個(gè)參數(shù)誤用字符串

如果你將一個(gè)字符串作為setTimeout/setTimeInterval,它會(huì)被傳給函數(shù)構(gòu)造函數(shù)并構(gòu)建一個(gè)新的函數(shù)。該操作流程很慢而且低效,并導(dǎo)致bug出現(xiàn)。

var hello = function(){

console.log("hello, fundebug !");

}

setTimeout("hello", 1000);

一個(gè)好的替代方法就是傳入函數(shù)作為參數(shù):

setInterval(logTime, 1000); // 將logTime函數(shù)傳入

setTimeout(function() { // 傳入一個(gè)匿名函數(shù)

logMessage(msgValue);

}, 1000);

十、未能成功使用strict mode

使用strict model會(huì)增加很多限制條件來加強(qiáng)安全和防止某些錯(cuò)誤的出現(xiàn),如果不使用strict mode,你就相當(dāng)于少了一個(gè)得力的助手幫你避免錯(cuò)誤:

· 更加容易debug

· 避免不小心定義了不該定義的全局變量

· 避免this隱式轉(zhuǎn)換

· 避免屬性名字或則參數(shù)值的重復(fù)使用

· eval()更加安全

· 無效地使用delete會(huì)自動(dòng)拋出錯(cuò)誤

關(guān)于Web前端中JavaScript常見BUG及修復(fù)方法是怎樣的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI