1. 程式人生 > >【JavaScript高階】7、函式高階(作用域與作用鏈)

【JavaScript高階】7、函式高階(作用域與作用鏈)

一、作用域

1. 理解
  * 就是一塊"地盤", 一個程式碼段所在的區域
  * 它是靜態的(相對於上下文物件), 在編寫程式碼時就確定了
2. 分類
  * 全域性作用域
  * 函式作用域
  * 沒有塊作用域(ES6有了)
3. 作用
  * 隔離變數,不同作用域下同名變數不會有衝突
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_作用域</title>
</head>
<body>
<script type="text/javascript">
/*  //沒塊作用域
  if(true) {
    var c = 3
  }
  console.log(c)*/

  var a = 10,
    b = 20
  function fn(x) {
    var a = 100,
      c = 300;
    console.log('fn()', a, b, c, x)  // fn() 100 20 300 10
    function bar(x) {
      var a = 1000,
        d = 400
      console.log('bar()', a, b, c, d, x)
    }

    bar(100)  // bar() 1000 20 300 400 100
    bar(200)  // bar() 1000 20 300 400 200
  }
  fn(10)
</script>
</body>
</html>

 二、作用域與執行上下文

1. 區別1
  * 全域性作用域之外,每個函式都會建立自己的作用域,作用域在函式定義時就已經確定了。而不是在函式呼叫時
  * 全域性執行上下文是在全域性作用域確定之後, js程式碼馬上執行之前建立
  * 函式執行上下文是在呼叫函式時, 函式體程式碼執行之前建立
2. 區別2
  * 作用域是靜態的, 只要函式定義好了就一直存在, 且不會再變化
  * 執行上下文是動態的, 呼叫函式時建立, 函式呼叫結束時就會自動釋放
3. 聯絡
  * 執行上下文(物件)是從屬於所在的作用域
  * 全域性執行上下文==>全域性作用域
  * 函式執行上下文==>對應的函式使用域

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_作用域與執行上下文</title>
</head>
<body>
<script type="text/javascript">
  var a = 10,
    b = 20
  function fn(x) {
    var a = 100,
      c = 300;
    console.log('fn()', a, b, c, x)  // fn() 100 20 300 10
    function bar(x) {
      var a = 1000,
        d = 400
      console.log('bar()', a, b, c, d, x)
    }

    bar(100)  // bar() 1000 20 300 400 100
    bar(200)  // bar() 1000 20 300 400 200
  }
  fn(10)
</script>
</body>
</html>

三、作用域鏈

1. 理解
  * 多個上下級關係的作用域形成的鏈, 它的方向是從下向上的(從內到外)
  * 查詢變數時就是沿著作用域鏈來查詢的
2. 查詢一個變數的查詢規則
  * 在當前作用域下的執行上下文中查詢對應的屬性, 如果有直接返回, 否則進入2
  * 在上一級作用域的執行上下文中查詢對應的屬性, 如果有直接返回, 否則進入3
  * 再次執行2的相同操作, 直到全域性作用域, 如果還找不到就丟擲找不到的異常
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_作用域鏈</title>
</head>
<body>
<script type="text/javascript">
  var a = 1
  function fn1() {
    var b = 2
    function fn2() {
      var c = 3
      console.log(c)  // 3
      console.log(b)  // 2
      console.log(a)  // 1
      console.log(d)  // 報錯
    }
    fn2()
  }
  fn1()
</script>

</body>
</html>

 四、作用域—面試題

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_作用域_面試題</title>
</head>
<body>
<script type="text/javascript">
  var x = 10;
  function fn() {
    console.log(x);
  }
  function show(f) {
    var x = 20;
    f();
  }
  show(fn);  // 10 此處15行相當於呼叫fn()函式,然後列印x,在fn()作用域內找不到,往上一級作用域找是全域性變數x=10
</script>
</body>
</html>

五、作用域—面試題2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_作用域_面試題2</title>
</head>
<body>
<script type="text/javascript">
  var fn = function () {
    console.log(fn)
  }
  fn()
  /*輸出:
  ƒ () {
    console.log(fn)
  }
   */

  var obj = {
    fn2: function () {
      //console.log(fn2)  // 此處會報錯,變數fn2在函式內部找不到再往上也找不到,上面的fn2實際上是obj物件的屬性即obj.fn2(或this.fn2)
      console.log(obj.fn2)
    }
  }
  obj.fn2()
</script>
</body>
</html>