iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 12
0
Modern Web

先你一步的菜鳥 - 從 0 開始的前端網頁設計系列 第 12

Day-12 hosting & Lexical Scope & function expression/declaration 雜談總集

  • 分享至 

  • xImage
  •  

在昨天我們提到了5個問題

  1. 為什麼定義在 function scope 內的都用 var ?用 let 不好嗎?const 呢?怎麼沒出現?
  2. 為什麼在 block scope 內不用 var 定義,是有甚麼原因嗎?
  3. let 和 var 差在哪裡?
  4. 為什麼在 block scope 內可以接到 fruit ,他不是還沒被定義嗎?
  5. 為什麼之前用 const 宣告 arrow function 而不是用 function 宣告,這有差別嗎?

今天就來好好講解一下這5個問題

1.為什麼定義在 function scope 內的都用 var ?用 let 不好嗎?const 呢?怎麼沒出現?

因為 var 的作用域是整個 function scope ,用 let、const 當然也可以,可是這樣就代表了他只能作用在當前那個 block,除非是定義在最上層的 function scope,不然很難共享,而 var 有 hosting 至少可以保證不會出現 error,當然也有人說 const 和 let 可以完全取代 var,這件事就見仁見智了,不過盡量避免使用 var 宣告這一點是不會錯的。

這邊可以稍微提一個有趣的東西 語彙範疇(Lexical Scope),js 是採用 Lexical Scope 設計的,當然還有另一個叫做動態範疇(dynamic scope)的,這邊就不多說了,目前不會碰到。

知道了 Lexical Scope 可以幹嘛呢,他有另一個講法 Static Scope,意思就是說是靜態的,也就是說我們定義在哪裡就會作用在哪裡,所以就可以有 local scope 、global scope 的差別。

現在我們知道 var 定義的作用域是 function scope ,那我們就可以實現一件事情:

 function scopeCheck(){
    var i=2
    function scope2(){
      console.log(i)
    }
    scope2()            // 2
  }
  scopeCheck()

你可以發現 i 並不是 scope2 的變數 ,i 也沒有經過 props 傳遞,但 scope2 卻可以輕易地擷取 i 的值,這時 i 對於 scope2 來說就是一個自由變數。

在 Lexical Scope 的設定內,如果一個變數被使用,但在他這個 scope 內找不到被定義的值的話,他就會一步一步往外面的 scope 找,直到找到這個變數被給值,所以我如果再用一個 scope1.5()包住 scope2(),並在裡面定義 i=3的話,scope2就會印出 3。如果一直找到 global scope 都沒有的話,就會報錯。

不管是var let const 都可以有這樣的效果,這樣是不是對作用域(scope)有更深入的理解了呢。

2.為什麼在 block scope 內不用 var 定義,是有甚麼原因嗎?

這個問題在講解 let 時因該就舉例得相當清楚了,這邊快速地複習一下,之所以不用 var 的原因是因為在 for loop 等循環區域裡,var 會被重複定值,造成區域變數互相汙染。

3.let 和 var 差在哪裡?

let 和 var 最大的差別在於:

  • let 不能被重複定值,var 可以。
  • let 作用範圍是 block scope,var 是 function scope。
  • 每一個被 let 宣告的變數可以在各自的 block 內獨立作用且不會互相影響,而 var 因為 hosting 和不嚴謹的宣告規則,很容易造成汙染,let 很安全 。

如果還有疑問的話,可以回去看一下昨天講解 let 的部分

4.為什麼在 block scope 內可以接到 fruit ,他不是還沒被定義嗎?

這是因為 var 的特性 hosting,用起來方便但非常危險,這邊做個複習,hosting 可以讓你不用宣告變數就提前使用,但給值還是要按照寫的順序來。

5.為什麼之前用 const 宣告 arrow function 而不是用 function 宣告,這有差別嗎?

首先必須要知道,函式宣告有分為函式陳述式(function expression)函式運算式(function declaration) 兩種。

這兩個最大的差別就是 function expression 會回傳一個值,並且可以被指定給一個變數,例如 arrow function :

const fun1 = () =>{console.log('expression')}

註:指定給 fun1 這個變數的,就是一個典型的匿名函式(anonymous function) ,且有匿名就有具名,只要是你有命名的函式,就可以被稱作具名函式(named function)。當然匿名函式雖然方便,但維護不易,還是建議乖乖把名字取好,不要跟自己過不去。

註:這邊提個題外話, expression 就是表達的意思,只要是你有給值的,例如:var i=1 這樣也是一個 expression。

而 function declaration 就是用 function 宣告的函式,他不能被指定給一個變數,必須調用他才能實作功能。

  function fruitName() {
    const fruit='apple'
    console.log(fruit);
  }
  fruitName()

這邊我們回到問題,arrow function 是 function expression,所以不能用 function 宣告。

我是 Chris,以上這些是關於碰到 scope 時可能會碰到的相關議題,裡面也包含了我遇到的一些問題,就一起帶出來給大家了,當然,我還有很多沒提到的部分,如果後面有碰到的話會再額外提出來給大家,明天見!


上一篇
Day-11 作用域和變數宣告
下一篇
Day-13 非同步 和 同步 - async/await & promise 物件了解 & callback function 和 IIFEs
系列文
先你一步的菜鳥 - 從 0 開始的前端網頁設計31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
yanzhong
iT邦新手 4 級 ‧ 2020-12-14 02:18:26

太讚了拉!!!
還先幫忙複習JS相關知識 /images/emoticon/emoticon02.gif

Chris iT邦新手 5 級 ‧ 2020-12-15 12:33:40 檢舉

謝謝你不嫌棄哈哈

如果有看到不太對的觀念也請務必指出喔!

我要留言

立即登入留言