js中var,let,const的區(qū)別及相關(guān)面試題講解
一. var
1. var聲明作用域
使用var在一個(gè)函數(shù)內(nèi)部定義一個(gè)變量,就意味著該變量將在函數(shù)退出時(shí)被銷毀:
function test(){ var a='hi' //局部變量 } test() console.log(a)//報(bào)錯(cuò) //如果省略操作符 function test(){ a='hi' //全局變量 } test() console.log(a) //'hi' //去掉var操作符之后,就變成了全局變量,只要調(diào)用一次test(),就會(huì)定義這個(gè)變量,并且可以在函數(shù)外部訪不 //推薦這樣做,容易造成混亂
2. 聲明提升 ,也就是把所有變量聲明都拉倒函數(shù)作用域的訂單,此外,使用var聲明同一個(gè)變量也沒(méi)有問(wèn)題;
function test(){ console.log(a) var a='hi' } test() // undefined //等價(jià)于下列代碼 function test(){ var a; console.log(a) a='hi' } //聲明同一個(gè)變量 function foo(){ var a=10; var a=20; var a=30; console.log(a); } foo(); //30
二. let
1.let 跟var 的作用差不多,最明顯的區(qū)別是,let聲明的范圍是塊作用域,而var聲明的范圍是函數(shù)作用域
//var 沒(méi)有塊作用域 塊作用域是是函數(shù)作用域的子集 因此let也沒(méi)有函數(shù)作用域 if(true){ var name='matt'; let age=26; console.log(name); //matt console.log(age); //26 } console.log(name); //matt console.log(age); //age沒(méi)有定義
2. let 也不允許同一個(gè)塊作用域出現(xiàn)冗余聲明
var name; var name; let age; let age; // age已經(jīng)聲明過(guò)了 //不在同一個(gè)塊中可以重復(fù)聲明 let age=30; console.log(age); //30 if(true){ let age=26; console.log(age); //26 } //在同一作用域內(nèi),不能混用 var 和 let 聲明同名變量,否則會(huì)拋出 SyntaxError。 var name; let name;//SyntaxError let age; var age; //SyntaxError
3. let 有暫時(shí)性死區(qū) 就是let聲明的變量不會(huì)在作用域中被提升
// var 會(huì)提升 console.log(name); //undefined var name='Matt' //let 不會(huì)提升. console.log(age)// age沒(méi)有定義 let age=16; 在let聲明之前的執(zhí)行瞬間被稱為"暫時(shí)性死區(qū)"
4. 使用let在全局作用域中聲明的變量不會(huì)變成window對(duì)象的屬性(var聲明的則會(huì))
var name='matt' console.log(window.name); //matt let age=26 console.log(window.age); //undefined
5.for循環(huán)中的let聲明和var 聲明
在let 出現(xiàn)之前,for循環(huán)定義的迭代變量會(huì)滲透到循環(huán)體外部;
for(var i=0;i<5;++i){ //循環(huán)邏輯 } console.log(i); //5 //改成使用let之后,這個(gè)問(wèn)題就消失了,因?yàn)榈兞康淖饔糜騼H限于for循環(huán)內(nèi)部; for(let i=0;i<5;++i){ //循環(huán) } console.log(i); //沒(méi)有定義
還有個(gè)面試經(jīng)常提及的問(wèn)題,在for循環(huán)的循環(huán)體內(nèi)定義一個(gè)定時(shí)器,循環(huán)結(jié)束后,查看結(jié)果
1. 使用var 的時(shí)候
for(var i=0;i<5;i++){ setTimeout(()=>console.log(i),1000) } //你可能會(huì)以為輸出0,1,2,3,4 //實(shí)際會(huì)輸出5,5,5,5,5
解釋: 我們知道,循環(huán)結(jié)束的條件是i=5, 從事件循環(huán)機(jī)制的角度來(lái)分析上面的代碼,是這樣的:
調(diào)用堆棧:用于存儲(chǔ)程序按順序調(diào)用的函數(shù)的詳細(xì)信息的堆棧。
1. 首先在Call Stack(調(diào)用堆棧)中執(zhí)行同步代碼var i=0,此時(shí)i小于5,執(zhí)行下一行代碼,發(fā)現(xiàn)是一個(gè)setTImeout計(jì)時(shí)器,它是一個(gè)宏任務(wù),這個(gè)時(shí)候會(huì)被推入到WEB API中,計(jì)時(shí)器開始執(zhí)行;
2. 執(zhí)行i++,在Call Stack中進(jìn)入下一次迭代循環(huán),重復(fù)上面操作
其實(shí)上面的代碼中WEB API一共存放過(guò)5個(gè)計(jì)時(shí)器,每個(gè)計(jì)時(shí)器進(jìn)入到WEB API, 1s之后就會(huì)被推 入到QUEUE(隊(duì)列)中(最后隊(duì)列中也會(huì)有5個(gè)計(jì)時(shí)器),等待EVENT LOOP(事件循環(huán))檢測(cè)到Call Stack為空時(shí),將QUEUE中每一個(gè)計(jì)時(shí)器推入到Call Stack執(zhí)行,最后全部代碼執(zhí)行完成,從調(diào)用棧 中退出
使用var 的時(shí)候,由于每一次循環(huán)得到的迭代變量會(huì)被上一次的覆蓋,最后i=5,退出循環(huán),迭代變 量也被泄露了出去了,每一個(gè)計(jì)時(shí)器引用同一個(gè)i,因此會(huì)打印5個(gè)5
《JavaScript高級(jí)程序設(shè)計(jì)4》: 是因?yàn)樵谕顺鲅h(huán)時(shí),迭代變量保存的是導(dǎo)致循環(huán)退出的值 : 5
在之后執(zhí)行超時(shí)邏輯時(shí),所有i都是同一個(gè)變量,因而輸出的都是同一個(gè)最終值
2.使用let 的時(shí)候
for(let j=0;j<5;j++){ setTimeout(()=>{ console.log('j',j) //1 2 3 4 5 }) }
個(gè)人理解 : for每次循環(huán)都是不同的塊級(jí)作用域,let聲明的變量是塊級(jí)作用域的,所以也不存在重復(fù)聲明的問(wèn)題
《JavaScript高級(jí)程序設(shè)計(jì)4》: 在使用let聲明迭代變量時(shí),js引擎在后臺(tái)會(huì)為每個(gè)迭代循環(huán)聲明一個(gè)新的迭代變量,每個(gè)setTimeout引用的都是不同變量實(shí)例,所以console.log()輸出的使我們期望的值,也就是循環(huán)執(zhí)行過(guò)程中每個(gè)迭代變量的值
這種每次迭代聲明一個(gè)獨(dú)立變量實(shí)例的行為適用于所有風(fēng)格的for循環(huán),包括for-in和for-of循環(huán)
三. const
1. const 的行為與let基本相同,唯一一個(gè)蟲重要的區(qū)別是用它聲明變量時(shí)必須同時(shí)初始化變量,且嘗試修改const聲明的變量會(huì)導(dǎo)致運(yùn)行時(shí)的錯(cuò)誤
const age=26; age=36; //TypeError: 給常量賦值
2.const聲明的限制只適用于它指向變量的引用,換句話說(shuō),如果const變量引用的是一個(gè)對(duì)象,那么修改這個(gè)對(duì)象內(nèi)部的屬性并不違反const的限制
const person={ } person.name='Matt'; //ok
3. js引擎會(huì)為for循環(huán)中的let聲明分別創(chuàng)建獨(dú)立的變量實(shí)例,雖然const變量跟let變量很相似,但是不能用const 來(lái)聲明迭代變量(因?yàn)榈兞繒?huì)自增);
for (const i=0; i<10;++i)() //TypeError: 給常量賦值
總結(jié)
到此這篇關(guān)于js中var,let,const的區(qū)別及相關(guān)面試題講解的文章就介紹到這了,更多相關(guān)js中var,let,const區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript中const、var和let區(qū)別淺析
- JavaScript ES6中const、let與var的對(duì)比詳解
- 5分鐘快速掌握J(rèn)S中var、let和const的異同
- 深入淺析var,let,const的異同點(diǎn)
- JavaScript中關(guān)鍵字?var、let、const的區(qū)別詳解
- JS變量中有var定義和無(wú)var定義的區(qū)別以及es6中l(wèi)et命令和const命令
- JavaScript變量聲明var,let.const及區(qū)別淺析
- 了解javascript中l(wèi)et和var及const關(guān)鍵字的區(qū)別
相關(guān)文章
TypeScript枚舉的基礎(chǔ)知識(shí)及實(shí)例
使用枚舉我們可以定義一些帶名字的常量,使用枚舉可以清晰地表達(dá)意圖或創(chuàng)建一組有區(qū)別的用例,下面這篇文章主要給大家介紹了關(guān)于TypeScript枚舉的基礎(chǔ)知識(shí)及實(shí)際用例,需要的朋友可以參考下2021-10-10Electron 使用 Nodemon 配置自動(dòng)重啟的方法
在Electron開發(fā)過(guò)程中,每次代碼修改后需手動(dòng)重新啟動(dòng)應(yīng)用,這一過(guò)程可以通過(guò)引入Nodemon工具自動(dòng)化,Nodemon能夠監(jiān)測(cè)文件變化并自動(dòng)重啟服務(wù)器,本文給大家介紹Electron 使用 Nodemon 配置自動(dòng)重啟,感興趣的朋友一起看看吧2024-09-09使用BootStrap實(shí)現(xiàn)懸浮窗口的效果
本文給大家分享使用BootStrap實(shí)現(xiàn)懸浮窗口的效果,神奇的 bootstrap就自帶了這個(gè)功能。所以就用bootstrap的popover插件做了,效果還不錯(cuò),感興趣的朋友參考下吧2016-12-12JavaScript動(dòng)態(tài)創(chuàng)建div屬性和樣式示例代碼
動(dòng)態(tài)創(chuàng)建div屬性和樣式在某些情況下還是比較實(shí)用的,下面為大家詳細(xì)介紹下js中div屬性和樣式的動(dòng)態(tài)創(chuàng)建,感興趣的朋友可以參考下2013-10-10JavaScript與jQuery中文檔就緒函數(shù)的區(qū)別
這篇文章主要介紹了JavaScript與jQuery中文檔就緒函數(shù)的區(qū)別,文章內(nèi)容介紹詳細(xì),具有一的的參考價(jià)值,需要的小伙伴可以參考一下2022-03-03javascript實(shí)現(xiàn)的字符串轉(zhuǎn)換成數(shù)組操作示例
這篇文章主要介紹了javascript實(shí)現(xiàn)的字符串轉(zhuǎn)換成數(shù)組操作,涉及javascript字符串與數(shù)組相互轉(zhuǎn)換、以及數(shù)組反轉(zhuǎn)相關(guān)操作技巧,需要的朋友可以參考下2019-06-06詳解關(guān)于html,css,js三者的加載順序問(wèn)題
這篇文章主要介紹了關(guān)于html,css,js三者的加載順序問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04js使用cookie實(shí)現(xiàn)記住用戶名功能示例
這篇文章主要介紹了js使用cookie實(shí)現(xiàn)記住用戶名功能,涉及javascript操作cookie讀寫及刪除實(shí)現(xiàn)用戶名的保存功能,需要的朋友可以參考下2019-06-06JS 實(shí)現(xiàn)雙色表格實(shí)現(xiàn)代碼
通過(guò)為<tr>元素添加屬性或類型選擇器,再通過(guò)CSS設(shè)置可以實(shí)現(xiàn)雙色表格,但如果表格很長(zhǎng),逐個(gè)元素添加可真麻煩。而且這樣的代碼維護(hù)起來(lái)不容易。所以比較好的方式是用JS實(shí)現(xiàn)。2009-11-11