js中var、let、const之間的區(qū)別
一、什么是變量
在讀這篇文章前,我們需要搞懂到底是什么變量,其實(shí)一句話就能概括:變量是一個(gè)可以保存任何數(shù)據(jù)類型值的命名占位符。本篇文章將會(huì)介紹以下知識(shí)點(diǎn):
- 什么是var、let、const
- 變量聲明規(guī)則
- 變量提升
- 塊作用域
- 暫時(shí)性死區(qū)
二、var關(guān)鍵字
2.1 初始化
初始化變量只需要在var關(guān)鍵字后面跟變量名即可:
var a; var b = 2;
上面這段代碼聲明了a和b兩個(gè)變量,a變量只是單純的聲明,并沒有賦值,js引擎遇到未賦值的變量時(shí),會(huì)自動(dòng)為其賦值一個(gè)值,這個(gè)值就是undefined;變量b在聲明的時(shí)候我們給它賦值了一個(gè)數(shù)字2,所以當(dāng)獲取變量b的時(shí)候,會(huì)得到一個(gè)number類型的2。
說到number類型,這里就不得不提到一個(gè)概念:JavaScript中的變量屬于松散類型,也就是變量的值可以變更為任何數(shù)據(jù)類型的值,但并不建議這么做,隨意更改變量的數(shù)據(jù)類型會(huì)導(dǎo)致代碼可讀性降低。
// 翻譯后是var a = undefined; var a; var b = 2; b = '2'; // 不建議這么做
在代碼開發(fā)過程中,有些場(chǎng)景需要?jiǎng)?chuàng)建多個(gè)變量,除了var a = 1; var b = 2;這種寫法,還可以使用,進(jìn)行更便利的創(chuàng)建多個(gè)變量:
// 使用逗號(hào)創(chuàng)建多個(gè)變量
var a = 1,
b = 2,
c = 3;
// 等同于
var a = 1;
var b = 2;
var c = 3;2.2 var聲明作用域
變量存在哪個(gè)作用域中是根據(jù)變量所聲明的場(chǎng)景位置決定,有兩種場(chǎng)景:全局、函數(shù)。在全局作用域中聲明var變量,該變量在任何地方都可以被訪問到,而且還可以通過window.變量名訪問。如果在函數(shù)內(nèi)部聲明變量,那么這個(gè)變量就只屬于這個(gè)函數(shù)自己的,外部訪問就會(huì)報(bào)錯(cuò),最后變量會(huì)在函數(shù)退出的時(shí)候被銷毀。
// 聲明全局變量
var a = 1;
// 訪問全局變量
console.log(a); // 1
console.log(window.a); // 1
// 聲明函數(shù)作用域內(nèi)的變量
function fun () {
var b = 2; // 只屬于fun函數(shù)的變量
console.log(b); // 2
};
fun(); // 2
console.log(b); // 報(bào)錯(cuò):b is not defined(變量b未定義)2.3 var的變量提升
變量提升其實(shí)就是在初始化的時(shí)候,var變量會(huì)提升到當(dāng)前作用域最頂部,并且每一個(gè)變量的值都是默認(rèn)undefined,當(dāng)js引擎執(zhí)行到變量賦值的代碼后,變量的值才會(huì)是我們想要的那個(gè)值,根據(jù)這個(gè)理論,來看下面一段代碼,思考一下代碼執(zhí)行的結(jié)果是什么:
var a = 1,
b = 2;
function fun (a) {
console.log(b);
var b = 6;
var b = 5;
console.log(a);
console.log(b);
};
console.log(b);
fun(4);
console.log(b);上面這段代碼其實(shí)并沒有復(fù)雜的交互,只是多次的訪問某些變量,會(huì)讓人有點(diǎn)眼花,沒關(guān)系,我們來一步一步的分解這些代碼,得到最終的結(jié)果,看是否和你的結(jié)果一樣:
- 全局作用域中出現(xiàn)了三個(gè)變量:
a、b、fun(函數(shù)名也是一個(gè)變量) - 在函數(shù)執(zhí)行前打印了全局作用域中的變量b,所以得到的是
2 - 調(diào)用函數(shù)并傳入?yún)?shù)值,開始執(zhí)行函數(shù)內(nèi)部代碼
- 此時(shí)函數(shù)內(nèi)部變量a和b都提升到了函數(shù)作用域頂部,并且值都是undefined
- 變量a被賦值4
- 打印變量b,此時(shí)變量還沒有被賦值,所以得到的是
undefined - 變量b開始被賦值,但遇到了兩個(gè)重名變量,最后一個(gè)變量會(huì)覆蓋之前的所有重名變量
- 獲取變量a,還記得嗎?在執(zhí)行參數(shù)的時(shí)候給變量a賦值了4,所以我們獲得的也是
4 - 因?yàn)橹暗淖兞縝被后面的變量b覆蓋了,所以現(xiàn)在獲取變量b,獲得的是
5 - 函數(shù)內(nèi)部代碼執(zhí)行完畢,開始獲取變量b的值
- 雖然函數(shù)內(nèi)部也有b變量,但那是屬于函數(shù)自己的,并且這個(gè)變量在函數(shù)執(zhí)行完后被銷毀了,所以我們只能獲取到全局作用域下的變量b,內(nèi)容是
2
所以最終結(jié)果是:2、undefined、4、5、2。
全局變量
全局變量除了在最外層聲明,其實(shí)還有另外一種聲明方式,不過這種方式并不受推薦,所以了解就好:
var a = 1; // 正常的聲明全局變量
function fun () {
b = 2; // 變量名前面沒有寫var,默認(rèn)成為全局作用域
};
// 因?yàn)楹瘮?shù)還沒有執(zhí)行,所以這塊會(huì)報(bào)錯(cuò)
console.log(b); // b not defined
fun();
console.log(b); // 2三、let聲明
3.1 塊級(jí)作用域
相比于var變量,let顯得更加精致,因?yàn)樗凶约旱穆暶鳒?zhǔn)則,其中最大的區(qū)別就是let聲明的范圍是塊級(jí)作用域,那么什么是塊級(jí)作用域呢,其實(shí)很好理解:{}符號(hào)中的區(qū)域被稱為塊級(jí)作用域,需要注意的是這個(gè)區(qū)域?qū)ar并沒有影響。
塊級(jí)作用域和函數(shù)作用域相似,控制著內(nèi)部變量的讀取權(quán)限
{ // 塊級(jí)作用域
let a1 = 2;
}
console.log(a1); // 報(bào)錯(cuò):a1 is not defined3.2 暫時(shí)性死區(qū)
在let創(chuàng)建之前的瞬間被稱為暫時(shí)性死區(qū),聽起來很高級(jí),其實(shí)就是在暫時(shí)性死區(qū)階段訪問不到let變量的意思,因?yàn)閘et變量沒有變量提升這一說;let還有一個(gè)特點(diǎn)就是不能被重復(fù)聲明,也就是說let變量不會(huì)像var變量一樣可以聲明多個(gè)重名變量,在let變量這會(huì)報(bào)錯(cuò)的。
{
console.log(b); // 因?yàn)闆]有變量提升,所以在聲明前訪問不到該變量,報(bào)錯(cuò):annot access 'b' before initialization
let b = 1;
}
let a = 1;
let a = 2; // 重名變量會(huì)報(bào)錯(cuò):caught SyntaxError: Identifier 'a' has already been declaredlet的全局作用域
雖然前面說let聲明的范圍是塊級(jí)作用域,但如果在最外層全局作用域里聲明let變量,也會(huì)被認(rèn)為是合法的全局變量,與var變量不同的是let全局作用域不能通過window.變量名訪問。
for循環(huán)中的let和var
for循環(huán)過程中會(huì)不斷產(chǎn)生新的塊級(jí)作用域,這個(gè)時(shí)候var和let變量值迭代更新就有了不同的變化:
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {};
console.log(i); // 報(bào)錯(cuò):i is not defined
for (var i = 0; i < arr.length; i++) {};
console.log(i); // 5上面代碼中第一個(gè)循環(huán)內(nèi),使用let創(chuàng)建了一個(gè)變量,當(dāng)我們?cè)谘h(huán)體外訪問該變量時(shí)竟然報(bào)錯(cuò)了!這是因?yàn)檠h(huán)體使用了{},所以形成了塊級(jí)作用域,此時(shí)在塊作用域外訪問let變量肯定會(huì)報(bào)錯(cuò)。當(dāng)我們?cè)L問var變量的時(shí)候?yàn)槭裁礇]有報(bào)錯(cuò)呢?那是因?yàn)関ar變量不受塊級(jí)作用域影響,它成為了全局作用域。
四、const聲明
const聲明被稱為常量,為了更好理解,下文還是用變量進(jìn)行介紹
const和let非常相似:不能聲明重名變量、存在暫時(shí)性死區(qū)、沒有變量提升、有塊級(jí)作用域限制。這些都是非常nice的規(guī)則,在此基礎(chǔ)上,const還增加了兩個(gè)規(guī)則:1、聲明時(shí)必須賦值;2、值不可修改;
聲明時(shí)必須賦值這個(gè)很好理解,就是在創(chuàng)建的時(shí)候必須給這個(gè)變量一個(gè)初始值。我們?cè)敿?xì)說一下值不可修改這一點(diǎn):
const a = '2'; a = 2; // 報(bào)錯(cuò)a變量已經(jīng)聲明,不能重復(fù)創(chuàng)建:entifier 'a' has already been declared
上面代碼首先我們創(chuàng)建了const變量并為其賦值字符串類型的'2',在第二行代碼實(shí)際上是想把數(shù)字類型的2賦值給剛剛創(chuàng)建的const變量中,這時(shí)候確保錯(cuò)了,由此可見const變量適合用在值不會(huì)變的場(chǎng)景。還有一種情況就是給const變量賦值數(shù)組和對(duì)象類型的值,因?yàn)檫@兩個(gè)數(shù)據(jù)類型屬于引用類型,所以只要在引用地址值不變的情況下,更改、新增、刪除對(duì)象或數(shù)組中的元素是不會(huì)報(bào)錯(cuò)的。
總結(jié)
根據(jù)本篇文章的介紹,我們可以得出一個(gè)結(jié)論:盡量不用var,變量值需要變化的時(shí)候使用let,值不需要改變的時(shí)候使用const。
| var | let | const | |
|---|---|---|---|
| 變量提升 | √ | × | × |
| 重復(fù)聲明相同名稱變量 | √ | × | × |
| 是否可以更改變量值 | √ | √ | × |
| 函數(shù)作用域 | √ | × | × |
| 塊作用域 | × | √ | √ |
到此這篇關(guān)于js中var、let、const之間的區(qū)別的文章就介紹到這了,更多相關(guān)js var let const內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- javascript中的var、let、const最佳實(shí)踐
- js中var,let,const的區(qū)別及相關(guān)面試題講解
- JavaScript中var、let和const的用法及區(qū)別詳解
- javascript中定義變量const和var有什么區(qū)別詳解
- Js中var,let,const的區(qū)別你知道嗎
- JavaScript變量中var,let和const的區(qū)別
- 淺談JS中var,let和const的區(qū)別
- javascript?變量聲明?var,let,const?的區(qū)別
- 面試官常問之說說js中var、let、const的區(qū)別
- JavaScript?ES6語(yǔ)法中l(wèi)et,const?,var?的區(qū)別
- javascript的var與let,const之間的區(qū)別詳解
- JavaScript中const和var的區(qū)別小結(jié)
相關(guān)文章
JavaScript分秒倒計(jì)時(shí)器實(shí)現(xiàn)方法
這篇文章主要介紹了JavaScript分秒倒計(jì)時(shí)器實(shí)現(xiàn)方法,可實(shí)現(xiàn)按照毫秒倒計(jì)時(shí)的效果,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
vite添加環(huán)境變量import.meta.env的方法
在不同的文件里面配置不同的環(huán)境變量,可以讓我們的配置更加容易維護(hù)和使用,這里我們說下vite配置環(huán)境變量和模式是怎么配置的,對(duì)vite環(huán)境變量相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧2023-10-10
JavaScript知識(shí)點(diǎn)總結(jié)(五)之Javascript中兩個(gè)等于號(hào)(==)和三個(gè)等于號(hào)(===)的區(qū)別
這篇文章主要介紹了JavaScript知識(shí)點(diǎn)總結(jié)(五)之Javascript中兩個(gè)等于號(hào)(==)和三個(gè)等于號(hào)(===)的區(qū)別的相關(guān)資料,需要的朋友可以參考下2016-05-05
window.print()局部打印三種方式(小結(jié))
本文主要介紹了window.print()局部打印三種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Javascript腳本實(shí)現(xiàn)靜態(tài)網(wǎng)頁(yè)加密實(shí)例代碼
這篇文章介紹了Javascript腳本實(shí)現(xiàn)靜態(tài)網(wǎng)頁(yè)加密實(shí)例代碼,有需要的朋友可以參考一下2013-11-11
JavaScript實(shí)現(xiàn)移動(dòng)端簽字功能
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)移動(dòng)端簽字功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
js原生實(shí)現(xiàn)FastClick事件的實(shí)例
下面小編就為大家?guī)硪黄猨s原生實(shí)現(xiàn)FastClick事件的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11

