變數的作用域 Scope


Posted by ericcch24 on 2020-10-16

變數的作用域 Scope 與 var, let, const 差異

  • 作用域:變數的生存範圍,==範圍以外就存取不到該變數==
    ### ES6 以前
  • 宣告變數用 var,==其變數生存範圍以 function 為單位==,在 function 以外就存取不到該變數。
var a = 'global'

function test() {
  var a = 1
  console.log(a)
}

test() // 1
console.log(a) // global
// 這邊存取不到 test() 內的 a = 1
---
var a = 10
function test() {
  a = 20
  console.log(a) // 20,
  // 作用域內找不到 a,所以找到 global 並改成 20
}
test()
console.log(a) // 20

---

// 等於建立 var a
function test() {
  a = 20 // 若沒有宣告變數,等於宣告一個 global
  console.log(a) // 20
}
test()
console.log(a) // 20
  • 在 function 中找不到要存取的變數時,會往更上層找要存取的變數,這個過程就會形成 ==scope chain==。
var a = 'global' // global scope
function test() { // test scope
  var b = 'test b'
  console.log(a, b) 
  // 輸出 global, test b,因為在 test 找不到 a,
  // 所以往上層找最後找到 global
  function inner() { // inner scope
    var b = 'inner b'
    console.log(a, b) 
    // 輸出 global, inner b,因為在 inner, test 都找不到 a,
    // 所以往上層找最後到 global
  }
  inner()
}
test()
console.log(a) // global
  • 作用域陷阱:==scpoe chain 的形成與 function 本身建立的位置有關,與在哪裡呼叫無關==
var a = "global"

function test() {
  var a = "test"
  other()
  // 雖然在這邊呼叫 other(),
  // 但 scope chain 是以 other() 建立時的位置形成
  // other scope -> global scope
  // 所以輸出 global
  // 而不是 other scope -> test scope -> global scope
}

function other() {
  console.log(a)
  // other() 在這邊建立
  // 所以 scope chain 往上層找的 a 就直接找到 global
}

test() // 輸出 global

---

var a = "global"

function test() {
  var a = "test"
  other()
  function other() {
     console.log(a)
  }
  // 因為在這邊建立 other(),所以 scope chain 是 
  // other scope -> test scope -> global scope
}

test() // 輸出 test

ES6

  • 宣告變數用 let, const,==其變數生存範圍以 block {} 為單位==。
function test() {
  let a = 5
  if (a === 5) { 
    let b = 10
    console.log(b) // 10
  }
  console.log(b) // error, b is not defined
  // 因為超出 {} 範圍,存取不到 b = 10
}

test()

---

function test() {
  for(var i = 0; i < 10; i++) {
    console.log("loop", i)
  }
  console.log("final", i)
}
test()
// loop 1, ..., 9
// final 10

function test() {
  for(let i = 0; i < 10; i++) {
    console.log("loop", i)
  }
  console.log("final", i)
}
test()
// loop 1, ..., 9
// i is not defined
// 因為 final i 已經超出 block 而存取不到迴圈的 i

var, let, const

  1. 除了這三個以外,還有一種方式是都不加關鍵字的,這種的會把變數變成全域變數,例如說 a = 3
  2. var 的 scope 是 function,可以重新宣告與賦值,需注意 hoisting
  3. let 的 scope 是 block,不能重新宣告,可以重新賦值,有 hoisting + TDZ
  4. const 的 scope 是 block,宣告時就要給初始值,不能重新賦值但可以在 object 更改內容,有 hoisting + TDZ

const 何時會出錯

  • primitive type:判斷數值有沒有改變,有改變就出錯
const a = 10
a = 20 
// 錯誤 Assignment to constant variable,不能重新賦值

---

const a
a = 20 // 錯誤,在宣告變數時就要給初始值
  • object:判斷記憶體位置有沒有改變,位置改變就出錯
const obj = {number: 1}
obj = {number: 2}
// Assignment to constant variable
// 錯誤,因為建立了新的物件,記憶體位置被改變

const arr = [3]
arr = [4] // 錯誤,建立新物件,記憶體位置被改變
---
const obj = {number: 1}
obj.number = 2 
// 可以,因為沒有改變記憶體位置,只是改內部的值

const arr = [3, 4]
arr.push(4) // 可以,沒有改變記憶體位置
arr[0] = 4 // 可以,沒有改變記憶體位置,只是改第 0 個的值
---
tags: Week16

#week16







Related Posts

數學證明(Mathematical Proofs)

數學證明(Mathematical Proofs)

5. 實際開發 ToDo List 案例

5. 實際開發 ToDo List 案例

ASP.NET Core Web API 入門教學 - 事前必備知識

ASP.NET Core Web API 入門教學 - 事前必備知識


Comments