JS - 宣告、Function、Hoisting

關於 JavaScript 中的 function、宣告(var / let / const)、Hoisting 的觀念筆記。


Function

一連串的處理、一群指令的集合。

定義 function() 起手式

定義有名字的 (一般)function

function functionName(參數1, 參數2

...)
{
...
    執行內容
    return 回傳值 (非必要)
}

定義沒有名字的 (匿名)function 

function (參數1, 參數2

...)
{
...
    執行內容
    return 回傳值 (非必要)
}

有名字 V.S 沒名字的 function ?

  • 有名字的 function 可更方便的在不同的地方被呼叫。
  • 沒名字的(匿名)function

    • 可存進變數裡,透過變數被呼叫。

        var total = function() {
            ... 
        }
    • 或透過 IIFE 的方式執行: (感謝泰安老師補充、Eureka解惑)

        (function() {
            ... 
        })()
  • 呼叫時的差異:
    有名字 function 在其前或後,都可呼叫成功。
    指給變數的匿名函數,在呼叫時必須在其變數定義行之後才可呼叫。


Function被呼叫時

function myFunction(x) {
    return x
}
console.log(myFunction)
// 印出整個function code
console.log(myFunction(2))
// 印出function回傳值

基礎寫法

  • 定義與呼叫function時一定要加()
  • 回傳值要加 return
  • return行之後的程式碼都不會執行(return表function結束)

箭號涵式 Arrow Function

  • 函式運算式

      function show(text){
        console.log(text)
      }
  • 箭號涵式

    • 寫法1 : (參數)=>(回傳值) > 宣告 函數名稱 (參數1,參數2) => ( 回傳值 )
      • 回傳值可以省略return 參數只有一個的時候可以省略括號 > 宣告 函數名稱 參數1 => ( 回傳值 )
      • 參數只有1個的時候可以省略() > 宣告 函數名稱 () => ( 回傳值 )
      • 沒有參數的時候不能省略括號
    • 寫法2 : (參數)=>{涵式內容} > 宣告 函數名稱 (參數1,參數2) => {
      > 涵式內容 > ... > > }

    • 例1:

        var show = (text) =>{
          console.log(text)
        }
    • 例2 (內裡匿名涵式):

        setTimeout(()=> { 
            console.log('text')
        }),1000);

Hoisting 提升

  • 先使用變數才宣告 var 時,不會噴錯、能執行但變數 = undefined

    • 因為只有提升宣告、沒有提升定義值

            console.log(num)
            var num = 1   // 是"undefined"、不是"Error"也不是1

  • 其他示例

      // 先使用變數再let宣告與賦值
      console.log(num1)
      let num1=1 
      // Uncaught ReferenceError: Cannot access 'num1' before initialization
      // 先使用變數再var宣告與賦值
      console.log(num2)
      var num2 = 1   
      // undefined
      // 先使用變數才賦值但無宣告
      console.log(num3)
      num3 = 2
      // Uncaught ReferenceError: num3 is not defined
      // 先使用變數才var宣告但無賦值
      console.log(num4)
      var num4   
      // undefined
      // 先使用變數才let宣告但無賦值
      console.log(num5)
      let num5   
      // Uncaught ReferenceError: Cannot access 'num5' before initialization

Scope 作用域

  • global scope - 包含function外(全域)
  • function scope - function內
  • block scope - block 內

宣告變數&常數-var / let / const

varletconst
意義宣告變數宣告變數宣告常數
宣告時可以先不指定值← (同var)必須指定值
宣告後可再次指定值← (同var)不可改變值
宣告後可再次宣告不可再次宣告不可再次宣告
範例var x
var x = 2
← (同var)const PI=3.14159
Scope
作用域
涵式區塊程式區塊{大括號內}
包含迴圈/判斷
← (同let)
  • 變數宣告不用指定類型
    可以隨時改變變數值的類型(儘量避免)
    型別資訊只存在在值或物件本身,變數本身沒有型別
  • 早期只能用var宣告變數,ES6增加 let、const
  • 如果沒有宣告而直接賦值(num = 2)也會成功
    因為 JS 自動視為全域變數宣告(但最好不要這樣)
print = (content) => {
    console.log(content)
}
  • Var

    1. var 沒有 function 時,scope 為整塊

       for(var i=0 ; i<5 ; i++){
         print(i)  //成功取得 i (=1、2、3、4)
       }
       print(i)    //成功取得 i (=5)
    2. var 在 function 內時,scope = function 內
      function 外讀不到

       function test(){
         for(var i=0 ; i<5 ; i++){
           print(i)  //成功取得 i (=1、2、3、4)
         }
       }
       print(i)    //無法取得 i
  • Let

    • let scope 只在{ }內
      { } 外就讀不到了

       for(let i=0 ; i<5 ; i++){
         print(i)  //成功取得 i (=1、2、3、4)
       }
       print(i)    //無法取得 i

參考資料

- [arrow function|MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

- [Hoisting|MDN](https://developer.mozilla.org/zh-TW/docs/Glossary/Hoisting)

- [IIFE|MDN](https://developer.mozilla.org/zh-TW/docs/Glossary/IIFE)

- [ASTRO X 五倍紅寶石 全端工程師實戰訓練營 | 蘇泰安](https://taian.su/)