国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

10個最常見的JavaScript問題

這篇具有很好參考價值的文章主要介紹了10個最常見的JavaScript問題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

如今,JavaScript幾乎是所有現(xiàn)代web應用程序的核心。這就是為什么JavaScript問題以及找出導致這些問題的錯誤是web開發(fā)人員的首要任務。

用于單頁應用程序(SPA)開發(fā)、圖形和動畫以及服務器端JavaScript平臺的強大的基于JavaScript的庫和框架并不是什么新鮮事。JavaScript在web應用程序開發(fā)的世界中確實變得無處不在,因此它是一項越來越重要的技能。

起初,JavaScript可能看起來很簡單。事實上,將基本的JavaScript功能構建到網頁中對于任何有經驗的軟件開發(fā)人員來說都是一項相當簡單的任務,即使他們是JavaScript新手。

然而,這種語言比人們最初認為的要微妙、有力和復雜得多。事實上,JavaScript的許多微妙之處導致了許多常見問題,這些問題阻礙了它的工作——我們在這里討論了其中的10個問題,在成為一名優(yōu)秀的JavaScript開發(fā)人員的過程中,需要注意和避免這些問題。

問題1:不正確的引用 this

隨著JavaScript編碼技術和設計模式多年來變得越來越復雜,回調和閉包中的自引用作用域也相應增加,這是造成JavaScript問題的 "this/that 混亂 "的一個相當普遍的來源。

考慮下面代碼:

Game.prototype.restart?=?function?()?{
????this.clearLocalStorage();
????this.timer?=?setTimeout(function()?{
????this.clearBoard();????//?What?is?"this"?
????},?0);
};

執(zhí)行上述代碼會出現(xiàn)以下錯誤:

Uncaught?TypeError:?undefined?is?not?a?function

上述錯誤的原因是,當調用 setTimeout()時,實際上是在調用 window.setTimeout()。因此,傳遞給setTimeout()的匿名函數(shù)是在window對象的上下文中定義的,它沒有clearBoard()方法。

傳統(tǒng)的、符合老式瀏覽器的解決方案是將 this 引用保存在一個變量中,然后可以被閉包繼承,如下所示:

Game.prototype.restart?=?function?()?{
????this.clearLocalStorage();
????var?self?=?this;???//?Save?reference?to?'this',?while?it's?still?this!
????this.timer?=?setTimeout(function(){
????self.clearBoard();????//?Oh?OK,?I?do?know?who?'self'?is!
????},?0);
};

另外,在較新的瀏覽器中,可以使用bind()方法來傳入適當?shù)囊茫?/p>

Game.prototype.restart?=?function?()?{
????this.clearLocalStorage();
????this.timer?=?setTimeout(this.reset.bind(this),?0);??//?Bind?to?'this'
};

Game.prototype.reset?=?function(){
????this.clearBoard();????//?Ahhh,?back?in?the?context?of?the?right?'this'!
};

問題2:認為存在塊級作用域

JavaScript開發(fā)者中常見的混亂來源(也是常見的錯誤來源)是假設JavaScript為每個代碼塊創(chuàng)建一個新的作用域。盡管這在許多其他語言中是對的,但在JavaScript中卻不是??紤]一下下面的代碼:

for?(var?i?=?0;?i?<?10;?i++)?{
????/*?...?*/
}
console.log(i);??//?輸出什么?

如果你猜測console.log()的調用會輸出 undefined 或者拋出一個錯誤,那你就猜錯了。答案是輸出10。為什么呢?

在大多數(shù)其他語言中,上面的代碼會導致一個錯誤,因為變量i的 "生命"(即使作用域)會被限制在for塊中。

但在JavaScript中,情況并非如此,即使在for循環(huán)完成后,變量i仍然在作用域內,在退出循環(huán)后仍保留其最后的值。(順便說一下,這種行為被稱為變量提升(variable hoisting)。

JavaScript中對塊級作用域的支持是通過let關鍵字實現(xiàn)的。Let關鍵字已經被瀏覽器和Node.js等后端JavaScript引擎廣泛支持了多年。

問題3:創(chuàng)建內存泄漏

如果沒有有意識地編寫代碼來避免內存泄漏,那么內存泄漏幾乎是不可避免的JavaScript問題。它們的發(fā)生方式有很多種,所以我們只重點介紹幾種比較常見的情況。

內存泄漏實例1:對不存在的對象的懸空引用?

考慮以下代碼:

var?theThing?=?null;
var?replaceThing?=?function?()?{
??var?priorThing?=?theThing;?
??var?unused?=?function?()?{
?????//?'unused'是'priorThing'被引用的唯一地方。
????//?但'unused'從未被調用過
????if?(priorThing)?{
??????console.log("hi");
????}
??};
??theThing?=?{
????longStr:?new?Array(1000000).join('*'),??//?創(chuàng)建一個1MB的對象
????someMethod:?function?()?{
??????console.log(someMessage);
????}
??};
};
setInterval(replaceThing,?1000);????//?每秒鐘調用一次?"replaceThing"。

如果你運行上述代碼并監(jiān)測內存使用情況,你會發(fā)現(xiàn)你有一個明顯的內存泄漏,每秒泄漏整整一兆字節(jié)!而即使是手動垃圾收集器(GC)也無濟于事。

因此,看起來我們每次調用 replaceThing 都會泄漏 longStr。但是為什么呢?

每個theThing對象包含它自己的1MB longStr對象。每一秒鐘,當我們調用 replaceThing 時,它都會在 priorThing 中保持對先前 theThing 對象的引用。

但是我們仍然認為這不會是一個問題,因為每次通過,先前引用的priorThing將被取消引用(當priorThing通過priorThing = theThing;被重置時)。

而且,只在 replaceThing 的主體和unused的函數(shù)中被引用,而事實上,從未被使用。

因此,我們又一次想知道為什么這里會有內存泄漏。

為了理解發(fā)生了什么,我們需要更好地理解JavaScript的內部工作。實現(xiàn)閉包的典型方式是,每個函數(shù)對象都有一個鏈接到代表其詞法作用域的字典式對象。

如果在replaceThing里面定義的兩個函數(shù)實際上都使用了priorThing,那么它們都得到了相同的對象就很重要,即使priorThing被反復賦值,所以兩個函數(shù)都共享相同的詞法環(huán)境。

但是一旦一個變量被任何閉包使用,它就會在該作用域內所有閉包共享的詞法環(huán)境中結束。而這個小小的細微差別正是導致這個可怕的內存泄露的原因。

內存泄漏實例2:循環(huán)引用

考慮下面代碼:

function?addClickHandler(element)?{
????element.click?=?function?onClick(e)?{
????????alert("Clicked?the?"?+?element.nodeName)
????}
}

這里,onClick有一個閉包,保持對element的引用(通過element.nodeName)。通過將onClick分配給element.click,循環(huán)引用被創(chuàng)建;即:element → onClick → element → onClick → element...

有趣的是,即使 element 被從dom中移除,上面的循環(huán)自引用也會阻止 element 和onClick被收集,因此會出現(xiàn)內存泄漏。

避免內存泄漏:要點

JavaScript的內存管理(尤其是垃圾回收)主要是基于對象可達性的概念。

以下對象被認為是可達的,被稱為 "根":

  • 從當前調用堆棧的任何地方引用的對象(即當前被調用的函數(shù)中的所有局部變量和參數(shù),以及閉包作用域內的所有變量)

  • 所有全局變量

只要對象可以通過引用或引用鏈從任何一個根部訪問,它們就會被保留在內存中。

瀏覽器中有一個垃圾收集器,它可以清理被無法到達的對象所占用的內存;換句話說,當且僅當GC認為對象無法到達時,才會將其從內存中刪除。不幸的是,很容易出現(xiàn)不再使用的 "僵尸 "對象,但GC仍然認為它們是 "可達的"。

問題4:雙等號的困惑

JavaScript 的一個便利之處在于,它會自動將布爾上下文中引用的任何值強制為布爾值。

但在有些情況下,這可能會讓人困惑,因為它很方便。例如,下面的一些情況對許多JavaScript開發(fā)者來說是很麻煩的。

//?下面結果都是?'true'
console.log(false?==?'0');
console.log(null?==?undefined);
console.log("?\t\r\n"?==?0);
console.log(''?==?0);

//?下面也都成立
if?({})?//?...
if?([])?//?...

關于最后兩個,盡管是空的(大家可能會覺得他們是 false),{}和[]實際上都是對象,任何對象在JavaScript中都會被強制為布爾值 "true",這與ECMA-262規(guī)范一致。

正如這些例子所表明的,類型強制的規(guī)則有時非常清楚。因此,除非明確需要類型強制,否則最好使用===和!==(而不是==和!=),以避免強制類型轉換的帶來非預期的副作用。(== 和 != 會自動進行類型轉換,而 === 和 !== 則相反)

另外需要注意的是:將NaN與任何東西(甚至是NaN)進行比較時結果都是 false。

因此,不能使用雙等運算符(==, ==, !=, !==)來確定一個值是否是NaN。如果需要,可以使用內置的全局 isNaN()函數(shù)。

console.log(NaN?==?NaN);????//?False
console.log(NaN?===?NaN);???//?False
console.log(isNaN(NaN));????//?True

問題5:低效的DOM操作

使用 JavaScript 操作DOM(即添加、修改和刪除元素)是相對容易,但操作效率卻不怎么樣。

比如,每次添加一系列DOM元素。添加一個DOM元素是一個昂貴的操作。連續(xù)添加多個DOM元素的代碼是低效的。

當需要添加多個DOM元素時,一個有效的替代方法是使用 document fragments來代替,從而提高效率和性能。

var?div?=?document.getElementsByTagName("my_div");
????
var?fragment?=?document.createDocumentFragment();

for?(var?e?=?0;?e?<?elems.length;?e++)?{??//?elems?previously?set?to?list?of?elements
????fragment.appendChild(elems[e]);
}
div.appendChild(fragment.cloneNode(true));

除了這種方法固有的效率提高外,創(chuàng)建附加的DOM元素是很昂貴的,而在分離的情況下創(chuàng)建和修改它們,然后再將它們附加上,就會產生更好的性能。

問題6:在循環(huán)內錯誤使用函數(shù)定義

考慮下面代碼:

var?elements?=?document.getElementsByTagName('input');
var?n?=?elements.length;????//?Assume?we?have?10?elements?for?this?example
for?(var?i?=?0;?i?<?n;?i++)?{
????elements[i].onclick?=?function()?{
????????console.log("This?is?element?#"?+?i);
????};
}

根據上面的代碼,如果有10個 input 元素,點擊任何一個都會顯示 "This is element #10"。

這是因為,當任何一個元素的onclick被調用時,上面的for循環(huán)已經結束,i的值已經是10了(對于所有的元素)。

我們可以像下面這樣來解決這個問題:

var?elements?=?document.getElementsByTagName('input');
var?n?=?elements.length;???
var?makeHandler?=?function(num)?{?
?????return?function()?{??
?????????console.log("This?is?element?#"?+?num);
?????};
};
for?(var?i?=?0;?i?<?n;?i++)?{
????elements[i].onclick?=?makeHandler(i+1);
}

makeHandler 是一個外部函數(shù),并返回一個內部函數(shù),這樣就會形成一個閉包,num 就會調用時傳進來的的當時值,這樣在點擊元素時,就能顯示正確的序號。

問題7:未能正確利用原型繼承

考慮下面代碼:

Baseobject?=?function(name)?{
????if?(typeof?name?!==?"undefined")?{
????????this.name?=?name;
????}?else?{
????????this.name?=?'default'
????}
};

上面代碼比較簡單,就是提供了一個名字,就使用它,否則返回 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'

當使用 delete 刪除該屬性時,就會返回一個 undefined,那么如果我們也想返回 default 要怎么做呢?利用原型繼承,如下所示:

BaseObject?=?function?(name)?{
????if(typeof?name?!==?"undefined")?{
????????this.name?=?name;
????}
};

BaseObject.prototype.name?=?'default';

BaseObject 從它的原型對象中繼承了name 屬性,值為 default。因此,如果構造函數(shù)在沒有 name 的情況下被調用,name 將默認為 default。同樣,如果 name 屬性從BaseObject的一個實例中被移除,那么會找到原型鏈的 name,,其值仍然是default。所以'

var?thirdObj?=?new?BaseObject('unique');
console.log(thirdObj.name);??//?->?Results?in?'unique'

delete?thirdObj.name;
console.log(thirdObj.name);??//?->?Results?in?'default'

問題8:為實例方法創(chuàng)建錯誤的引用

考慮下面代碼:

var?MyObject?=?function()?{}
????
MyObject.prototype.whoAmI?=?function()?{
????console.log(this?===?window???"window"?:?"MyObj");
};

var?obj?=?new?MyObject();

現(xiàn)在,為了操作方便,我們創(chuàng)建一個對whoAmI方法的引用,這樣通過whoAmI()而不是更長的obj.whoAmI()來調用。

var?whoAmI?=?obj.whoAmI;

為了確保沒有問題,我們把 whoAmI 打印出來看一下:

console.log(whoAmI);

輸出:

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

Ok,看起來沒啥問題。

接著,看看當我們調用obj.whoAmI() 和 whoAmI() 的區(qū)別。

obj.whoAmI();??//?Outputs?"MyObj"?(as?expected)
whoAmI();??????//?Outputs?"window"?(uh-oh!)

什么地方出錯了?當我們進行賦值時 var whoAmI = obj.whoAmI,新的變量whoAmI被定義在全局命名空間。

結果,this的值是 window,而不是 MyObject 的 obj 實例!

因此,如果我們真的需要為一個對象的現(xiàn)有方法創(chuàng)建一個引用,我們需要確保在該對象的名字空間內進行,以保留 this值。一種方法是這樣做:

var?MyObject?=?function()?{}
????
MyObject.prototype.whoAmI?=?function()?{
????console.log(this?===?window???"window"?:?"MyObj");
};

var?obj?=?new?MyObject();
obj.w?=?obj.whoAmI;???//?Still?in?the?obj?namespace

obj.whoAmI();??//?Outputs?"MyObj"?(as?expected)
obj.w();???????//?Outputs?"MyObj"?(as?expected)

問題9:為 setTimeout 或 setInterval 提供一個字符串作為第一個參數(shù)

首先,需要知道的是為 setTimeout 或 setInterval 提供一個字符串作為第一個參數(shù),這本身并不是一個錯誤。它是完全合法的JavaScript代碼。這里的問題更多的是性能和效率的問題。

很少有人解釋的是,如果你把字符串作為setTimeout或setInterval的第一個參數(shù),它將被傳遞給函數(shù)構造器,被轉換成一個新函數(shù)。這個過程可能很慢,效率也很低,而且很少有必要。

將一個字符串作為這些方法的第一個參數(shù)的替代方法是傳入一個函數(shù)。

setInterval("logTime()",?1000);
setTimeout("logMessage('"?+?msgValue?+?"')",?1000);

更好的選擇是傳入一個函數(shù)作為初始參數(shù):

setInterval(logTime,?1000);?
????
setTimeout(function()?{??????
????logMessage(msgValue);?????
},?1000);

問題10:未使用 "嚴格模式"

"嚴格模式"(即在JavaScript源文件的開頭包括 "use strict";)是一種自愿在運行時對JavaScript代碼執(zhí)行更嚴格的解析和錯誤處理的方式,同時也使它更安全。

但是,不使用嚴格模式本身并不是一個 "錯誤",但它的使用越來越受到鼓勵,不使用也越來越被認為是不好的形式。

以下是嚴格模式的一些主要好處:

  • 使得調試更容易。原本會被忽略或無感知的代碼錯誤,現(xiàn)在會產生錯誤或拋出異常,提醒我們更快地發(fā)現(xiàn)代碼庫中的JavaScript問題,并引導更快地找到其來源。

  • 防止意外的全局變量。在沒有嚴格模式的情況下,給一個未聲明的變量賦值會自動創(chuàng)建一個具有該名稱的全局變量。這是最常見的JavaScript錯誤之一。在嚴格模式下,試圖這樣做會產生一個錯誤。

  • 消除this 強迫性。在沒有嚴格模式的情況下,對 null 或 undefined 的 this 值的引用會自動被強制到全局。在嚴格模式下,引用null或undefined的this值會產生錯誤。

  • 不允許重復的屬性名或參數(shù)值。嚴格模式在檢測到一個對象中的重復命名的屬性(例如,var object = {foo: "bar", foo: "baz"};)或一個函數(shù)的重復命名的參數(shù)(例如,function foo(val1, val2, val1){})時拋出一個錯誤,從而捕捉到你的代碼中幾乎肯定是一個錯誤,否則你可能會浪費很多時間去追蹤。

  • 使得eval()更加安全。eval()在嚴格模式和非嚴格模式下的行為方式有一些不同。最重要的是,在嚴格模式下,在eval()語句中聲明的變量和函數(shù)不會在包含的范圍內創(chuàng)建。(在非嚴格模式下,它們是在包含域中創(chuàng)建的,這也可能是JavaScript問題的一個常見來源)。

  • 在無效使用delete的情況下拋出錯誤。delete 操作符(用于從對象中刪除屬性)不能用于對象的非可配置屬性。當試圖刪除一個不可配置的屬性時,非嚴格的代碼將無聲地失敗,而嚴格模式在這種情況下將拋出一個錯誤。

寫在最后

以上就是我今天跟你分享的10個JavaScript中最常見的問題,不知道這10個問題中有沒有你不知道?如果有的話,請認真學習,如沒有的話,請當作復習。文章來源地址http://www.zghlxwxcb.cn/news/detail-431961.html

到了這里,關于10個最常見的JavaScript問題的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • javascript:void(0)用法及常見問題解析

    javascript:void(0) 在 JavaScript 中是一個常見的用法,主要用于阻止鏈接的默認行為。當你在一個 a 標簽的 href 屬性中使用 javascript:void(0) ,該鏈接點擊后不會有任何默認的頁面跳轉或刷新行為。 下面是這個用法的一些細節(jié)和示例: 通常,一個 a 標簽會導航到一個新的 URL。但是,

    2024年03月17日
    瀏覽(27)
  • 前端面試:常見的HTML、CSS和JavaScript問題解答

    前端開發(fā)面試中,HTML、CSS和JavaScript是必考點。以下是常見的HTML、CSS和JavaScript問題的解答,希望能對前端開發(fā)者的面試有所幫助。 文檔類型(doctype)的作用是什么? 文檔類型用來告訴瀏覽器當前頁面使用哪種HTML標準進行渲染。不同的HTML標準支持的標簽和屬性有所差異,因

    2024年02月08日
    瀏覽(32)
  • javaScript和jQuery獲取、設置textarea標簽的內容(常見問題)

    昨天晚上在寫代碼的時候前端遇到一個bug,在js取值textarea中,我使用了getElementById方法對textarea標簽取值,但不論如何取值,始終無法成功取到頁面上輸入的值并進行Ajax請求,一開始以為是ajax與后端接口之間數(shù)據傳輸出問題了,后來經過排查,就是對于textarea標簽取值失敗的

    2024年02月05日
    瀏覽(21)
  • 50個最受歡迎的大數(shù)據面試問題

    50個最受歡迎的大數(shù)據面試問題

    大數(shù)據時代才剛剛開始。隨著越來越多的公司傾向于大數(shù)據來運營他們的業(yè)務,對人才的需求空前高漲。這對您意味著什么?如果您想在任何大數(shù)據崗位上工作,它只會轉化為更好的機會。您可以選擇成為數(shù)據分析師,數(shù)據科學家,數(shù)據庫管理員,大數(shù)據工程師,Hadoop大數(shù)據

    2023年04月14日
    瀏覽(21)
  • 【解決(幾乎)任何機器學習問題】:超參數(shù)優(yōu)化篇(超詳細)

    【解決(幾乎)任何機器學習問題】:超參數(shù)優(yōu)化篇(超詳細)

    這篇文章相當長,您可以添加至收藏夾,以便在后續(xù)有空時候悠閑地閱讀。 有了優(yōu)秀的模型,就有了優(yōu)化超參數(shù)以獲得最佳得分模型的難題。那么,什么是超參數(shù)優(yōu)化呢?假設您的機器學習項?有?個簡單的流程。有?個數(shù)據集,你直接應??個模型,然后得到結 果。模型

    2024年02月21日
    瀏覽(24)
  • Debian 10配置apt源常見問題

    Debian 10配置apt源常見問題

    目錄 ? 一:配置本地apt源沒有發(fā)現(xiàn)文件 ?解決方案 ?二:apt下載bind9報錯E: Package \\\' bind9\\\' has no installation candidate 方法一: 方法二:更新不報錯但是安裝依舊報錯E: Package \\\' bind9\\\' has no installation candidate ? ? ? 方法一: ?網上大部分人說要更新,然后 我反正,沒有用,我希望對你

    2023年04月16日
    瀏覽(30)
  • 常見Charles在Windows10抓包亂碼問題

    常見Charles在Windows10抓包亂碼問題

    廢話不多說 直接開整 最近反復安裝證書還是亂碼 網上各種百度還是不行 首先計算機查看安裝好的證書 certmgr.msc 找到并刪除掉 重新安裝證書 具體解決方法: 第一步:點擊 【工具欄–Proxy–SSL Proxying Settings…】 第二步:配置請求的域名和端口號,*表示任意 再Charles.ini文件中

    2024年02月14日
    瀏覽(20)
  • windows10系統(tǒng)安裝docker desktop超常見問題

    windows10系統(tǒng)安裝docker desktop超常見問題

    問題報錯: An unexpected error was encountered while executing a WSLcommand. Common causes include access rights issues, which occurafter waking the computer or not being connected to your domain/active directory. Please try shutting WSL down (wsl --shutdown) and/or rebooting yourcomputer. If not sufficient, WSL may need to be reinstalled fully. As alas

    2024年02月11日
    瀏覽(23)
  • Python速查表;騰訊大佬的AIGC設計應用匯總;這個世界需要10億開發(fā)者;67個最常用AI工具清單 | ShowMeAI日報

    Python速查表;騰訊大佬的AIGC設計應用匯總;這個世界需要10億開發(fā)者;67個最常用AI工具清單 | ShowMeAI日報

    ?? 日報周刊合集 | ?? 生產力工具與行業(yè)應用大全 | ?? 點贊關注評論拜托啦! 隨著AIGC浪潮的興起,越來越多小伙伴嘗試著使用 GPT 類工具開發(fā)小程序、網頁、小游戲等應用,也意識到 Python 編程是繞不過去知識門檻。 推薦一份 ShowMeAI 制作的 Pyhton 速查表,涵蓋了 Python 3 編

    2024年02月06日
    瀏覽(31)
  • ES常見問題(1)-解決ElasticSearch每次只能返回10條數(shù)據

    ES常見問題(1)-解決ElasticSearch每次只能返回10條數(shù)據

    使用ElasticSearch查詢分頁數(shù)據 有時候,我們需要使用ElasticSearch來分詞查詢,并分頁返回指定的數(shù)據條數(shù),但是當我們每次想得到分頁數(shù)據條數(shù)超過十條的時候,ElasticSearch總是只能返回十條 因為ElasticSearch為了查詢的速度,在默認的情況下已經設置了分頁數(shù)據只能返回10條,所

    2024年02月11日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包