iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 1
0
Modern Web

一步一腳印-紮紮實實學es6系列 第 1

搞懂變數作用域

緣起

這個主題有什麼好寫的呢?
在其他語言相信大家都沒有什麼問題
偏偏js 有許許多多難以理解的地方
或者說有點「玄」
好像在說鬼故事…
相信用過一陣子js 的人都了解我在說什麼
「js真是太奇怪啦!」

如果你有以下問題,就跟我一起來搞清楚吧

  • 為什麼有時候not defined, 有時候undefine ?
  • 我以為的區域變數,卻變成全域了(黑人問號??)
  • 我以為的不是我以為的(??)

言歸正傳,我們開始吧

變數宣告方式

js 的變數宣告有三種方式

  • var
  • let
  • const

首先來搞懂var 的作用
var 是宣告一個變數,向記憶體要一塊空間來存放變數的值
所以說,如果沒有給值的話
javascript 會預設給一個值,叫做「undefined」

var k=10;

這邊先把他拆成2個步驟來看

var k;
k=10;
而這2個步驟不會放在一起執行
後面再來說

拉昇

以作用域的觀點來看
在var 的世界裡
如果要區分全域(global)與區域(local)
只有用function 來區分

var a=5;
console.log(a);
function foo(){
    console.log("in function , a:"+a); //a:5
    var b=5; 
}
console.log(b) ; //b is not defined

顯而易見的,結果會如預期般
在函式中所宣告的 b 無法被外部存取到
https://ithelp.ithome.com.tw/upload/images/20181001/20110579hVeWt9dTBB.png]
而呼叫foo()時,a 做為全域變數,可以被存取
而b 在function 中被宣告,所以無法被reference
一切都很合乎常理…
但是如果在我們宣告之前就呼叫變數呢?

console.log("global variable c:"+c)
var c=10;

我們預期會印出 c is not defined
但是卻印出 c 有一個 undefine 的值

https://ithelp.ithome.com.tw/upload/images/20181001/20110579QgIk3Xcfn1.png

這就是有名的**拉昇(hositing) **
javascript 會將你有宣告的變數拉到程式執行的最前面,在你賦值之前先幫你宣告
直到程式執行到你賦值的那行才會assign

同樣的事情也出現在function內
https://ithelp.ithome.com.tw/upload/images/20181001/20110579nlUeie0WP5.png

是否開始有點小抓狂?

再來一個更抓狂的範例
也許你有發現,js 中不用宣告也可以
那這到底是什麼樣的變數呢?
糾究是他直接幫我們加上了var
亦或是自動幫我們做了什麼事呢?

a=15;
function foo(){
b=80;
}
foo();
console.log("a:"+a);
console.log("b:"+b);

事實上我一直以為是會自動加上var ,是可以省略不寫的
然後很合理的,b 是區域變數,外面是叫不到的
一切都很完美。

沒想到… 令人抓狂的是
https://ithelp.ithome.com.tw/upload/images/20181001/20110579QrsjCZZYUd.png
竟然呼叫得到!
沒加var 的結果是都變成全域變數了阿!
所以最好還是別忘記var
除非你知道你在做什麼…


重覆宣告

如果重覆宣告會發生什麼事呢?

考慮以下狀況

var k=100;
var k;
console.log(k);

請選擇

  1. 彈出k已被經宣告過的錯誤
  2. k=100
  3. k=undefined

很好,根據事實
k=100 ...
好了,我知道了,原來重覆宣告的時候,第2個宣告是無效的
但真的是這樣嗎??

var k=100;
var k=999;
console.log(k);

很好,根據剛才的結論,k=100
....
但事實證明
https://ithelp.ithome.com.tw/upload/images/20181002/20110579imptthyo5C.png
...
在這邊又嘔出幾碗鮮血

https://ithelp.ithome.com.tw/upload/images/20181002/20110579uZvlqsn4Lq.png

還是因為剛才提到的拉昇問題
他會將var 的變數都先拆解成2個步驟,移到賦值之前
先宣告,其後再賦值
而重覆宣告同樣的變數是可以的
所以在重覆宣告時,若不給值,則不會再賦值。
若有給值,則只會跑賦值的那段。
真是... 奇怪的設計。

@$^^&%^*%$#...

變數泄漏

而var 不受控制的還有變數泄漏的問題

如同剛才說的,var 只有在function 內才能將變數鎖在裡面

所以對於常用的for 迴圈,在迴圈跑完後還是能呼叫得到用來計數的i 的值
範例如下:
https://ithelp.ithome.com.tw/upload/images/20181001/20110579l4vUAmwZAj.png
如上所示
i 是會被外部所存取到的

如何還我們一個清淨呢??

下一篇將來討論let 與const 的使用方法

是否能幫助我們解決這些問題


下一篇
搞懂變數作用域(2)- let 與const
系列文
一步一腳印-紮紮實實學es630
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言