iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0
自我挑戰組

JavaScript101與人生幹話系列 第 13

JavaScript101與人生幹話 - var、let、const的差別

  • 分享至 

  • xImage
  •  

var、let、const的差別

1.為什麼要宣告變數?-全域區域汙染

1.先了解什麼是全域屬性

宣告一個全域屬性,範例如下

a = 1 ;

沒有看錯,就是這麼簡單就完成了全域屬性的宣告。

但是全域屬性有個問題

function fna(){
a = 1;
}
function fna1(){
a = 2;
}
console.log(a);//2

console.log(a) 最後會顯示a為2,也就是說後面的所宣告的a = 2;全域屬性把前面宣告a = 1;的全域屬性給覆蓋了。

a = 1;

function fna(){
a = 2;
}
console.log(a);//2

這次我們試著在function外宣告全域屬性,但是可以看到依然被 function a(){}內部的 a = 2; 給覆蓋掉。

2.變數宣告-作用域

為了處理全域屬性覆蓋的問題,需要宣告變數,變數宣告之後會有作用域

function fna(){
var a = 1;
}
function fna1(){
var a = 2;
}
console.log(a);// a is not defined

根據上面的範例會看到a is not defined 因為在function內宣告a為變數的時候,a的做用範圍只會存在在function內,兩function的a不會互相影響。

3.屬性可以被刪除,變數不能被刪除

//宣告全域屬性
a = 0 ;
delete window.a
console.log(window)//會找不到a
//宣告變數
var b = 1 ;
delete window.b
console.log(window)// b屬性存在
console.log(b)//1

4.var的特性

1.詞法做用域

var a = 0;
function fna (){
  console.log(a)//0
}
function fna1 (){
var a = 1 ;
  console.log(a)//1
}
console.log(a)//0

從上的範例可以看到 function fna會向外查找var a = 0;而且function fna1內部宣告的var a = 1不會影響外面的var a = 0

2.var的作用域在程式碼撰寫完得當下就已經確定了

var a = 0;
function fna (){
console.log(a);
}
function fnb (){
var a = 1;
console.log(a)
}

fnb()//1
fna()//0

可以看到fna執行後向外查找var a = 0;而且fnb的執行順序也不會影響var a = 0;

var a = 0;
function fna (){
console.log(a);//0
}
function fnb (){
var a = 1;
fna()
}
fnb()

無論fna()在哪裡執行(被包在fnb內)最後還是會回到從第2行開始執行fna,一樣向外查找var a = 0;而不是fnb內所宣告的變數var a= 1;

3.var的其他特性

1.重複宣告也沒問題。

var a = 1;
var a = 0;
var a = 5;
console.log(a)//5

2.從外面是找不到function內部宣告的變數

function fna(){
var a = 1;
}
console.log(a)// a is not defind

3.可以從外向內找區塊內所宣告的變數

{
var a = 1;
}
console.log(a)//1

4.在for迴圈中用var宣告的i如果會洩漏出來
for迴圈屬於block

for(var i = 0 ; i<10;i++){
console.log(i)//0 1 2 ...9
}
console.log(i)//10

從上面的例子中看到for迴圈內i= 10的後就該停下來,不會顯示,但是因為用var宣告的變數是可以由外面往區塊內讀取所以才會讀到i = 10

5.在for迴圈中用setTimeout

for(var i = 0 ; i<10;i++){
setTimeout(function(){
console.log(i)//10 ... 10 出現10次10
})
}

上述範例中會出現10個10的原因,是因為setTimeout執行的位置都會是在javascript的最後,所以會取到i值為10

4.hoisting

在還沒宣告變數以前常試取得變數就是hoisting

console.log(a)//a is not definded  hoisting
var a = 1;
console.log(a)//1

let與var的差異

1.先來看看let在區塊內宣告後再重區塊外取得用let宣告的變數會怎麼樣?

{
let a = 1;
}
console.log(a)// a is not definded

與用var不同會取不到區塊內所宣告的變數,只有let會被區塊限制。

2.再來試function內會怎麼樣

function fna(){
let a = 0;
}
console.log(a)// a is not definded

這一點與var是相同的,作用域都會被function限制,從外面取不到function的變數

3.這時候先看看for迴圈中i用var宣告時setTimeout的情況

for(var i = 0 ; i<10;i++){
setTimeout(function(){
console.log(i)//10...10
})
}

會出現上面的情況是因為var在迴圈中會洩漏到全域變數,i=10賦值然後再繼續跑setTimeout,再來看看for迴圈中i用let宣告時setTimeout的情況

for(let i = 0 ; i<10;i++){
setTimeout(function(){
console.log(i)//0 ... 9
})
}

這個時候就能正常運作了,因為i不會從區塊洩漏出來

4.使用let所宣告的變數,不會出現在windo上

let a = 0;
var b =1;
console.log(windo);//會找不到a 但是會找到b:1

5.不能使用let重複宣告相同的變數

let a = 0;
let a =1;
// 'a' has already been declared

與用var可以重複宣告相同的變數不同,let不能在同區塊重複宣告相同的變數。

6.暫時性死區(TDZ)

function fna(a){
console.log(a)
var a = 2;
}
fna(1)//1

使用var 宣告變數結果是1

function fna(a){
console.log(a)
let a = 2;
}
fna(1)//  'a' has already been declared

不允許let 或 const 宣告值之前取得值,這樣子會造成暫時性死亡。
原因在準備階段時原本使用var宣告的變數是undefined,但在使用const、let時則是什麼都沒有(不是null),所以就無法取得執行之後的變數賦值。

function fn(){
    console.log(a)
    let a = 'a'
}
fn() // Uncaught ReferenceError: Cannot access 'a' before initialization

// 準備階段
   let a ; // 但是這個時候 a什麼都沒有
// 執行階段
   console.log(a) // 因為準備階段a什麼都沒有,自然取不到值而報錯
   a = 'a' // 因為上一行報錯所以這行不會執行

let與var的差異簡易對照表

情況 var let、const
從外取得區塊內所宣告的值 不可
從外取得function內所宣告的值 不可 不可
重複宣告變數 不可
存在window上 存在 不存在
暫時性死亡

let與const的差異

1.重複賦值

let a = 0;
a = 5;
a = 'string';
a = true;
console.log(a)//true

使用let 宣告的變數可以重複賦值

const a = 0;
a = 5;
a = 'string';
a = true;
console.log(a)//Assignment to constant variable

會報錯不能重複賦值

2.物件傳參考

const a = {
   name:'Joy'
}
a.name = 'Mary'
a.job = 'teacher'
console.log(a)//{
   name:'Mary
   job:'teacher'
}

因為物件傳參考的特性所以使用const宣告的物件可以修改與增加屬性值

const a = {
   name:'Joy'
}
 a = {
   name:'Mary'
}

console.log(a)//Assignment to constant variable
}

因為 a ={ name:'Mary'}等於又賦值了一個新的物件,因為const不能重複宣告所以報錯

如果物件的指向會改變(再次賦值),則使用let宣告物件,如果物件不會改變指向則推薦使用const

let與const的差異總結

情況 const let
變數重複賦值 不可

補充說明let 的作用在function的作用域

範例1

let a = 2;
function num(){
  let a = 5;
  console.log(a)
}
num()//5
console.log(a)//2

num函式印出5
console.log印出2

let a = 2;
function num(){
  a = 5;
  console.log(a)
}
num()//5
console.log(a)//5

這裡num函式與console.log皆印出5
原因是因為在function內沒有宣告a的變數,所以會"向外"找變數,所以全域變數的a會被重新賦值

let a = 2;
function num(){
  let a =3;
  a = 5;
  console.log(a)
}
num()//5
console.log(a)//2

num函式印出5
console.log印出2
因為function內有宣告a變數所以在function內,對a賦值指會對function內的a影響,對全域變數的a沒有影響。


參考資料
JavaScript 那個 let, const, var 到底差在哪?

人生幹話-生科仍是持續的呼弄

這個呼弄在第四年依然持續,在這第二家公司的第四年,老闆說是因為我們沒有在國外設立據點,所以R藥廠與其他的大藥廠不認為公司是個咖,我們要前進美洲與歐洲,同時間也呼弄到了日本的藥廠買了沒什麼用的大型機台與簽最低額度採購試劑的合約,為被呼弄得日本藥廠默哀3秒,既然要在國外設點那勢必要找一個在國外的CEO,果然那個要去國外的CEO也跟老闆一樣很會打雞血、鼓舞人心說幹話話空氣大餅與呼弄股東


上一篇
JavaScript101與人生幹話- 表達式(Expression)與陳述式(Statement)
下一篇
JavaScript101與人生幹話 - XMLHttpRequest
系列文
JavaScript101與人生幹話30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言