天天看點

javaScript作用域以及作用域鍊

什麼是作用域

作用域指的是變量存在的範圍。

  • 在 JavaScript 中, 對象和函數同樣也是變量,可以了解作用域為可通路變量,對象,函數的集合
在 ​

​ES5​

​​ 的規範中,​

​JavaScript​

​​ 隻有兩種作用域:一種是全局作用域,變量在整個程式中一直存在,所有地方都可以讀取;

另一種是函數作用域,變量隻在函數内部存在。​​

​ES6​

​ 又新增了塊級作用域

全局作用域

所有頂層函數聲明或者大括号之外定義的變量,都在全局作用域裡。

function fxFn () {
  fxs = 2
}

var fx = 1
console.log(window.fx) // 1
// console.log(fxs) 未定義
fxFn() // 執行後fxs成為全局變量
console.log(fxs) // 2      

​​var聲明的變量與不使用var聲明的變量差別​​

局部作用域(函數作用域與塊級作用域)

函數作用域

在 ​

​JavaScript​

​ 中,任何定義在函數體内的變量或者函數都将處于函數作用域中,這些變量通常無法被在函數外部使用

  • 局部變量在函數開始執行時建立,函數執行完後局部變量會自動銷毀。
  • 當函數體内局部變量和函數體外的變量重名的話,内部局部變量将會遮蓋同名的全局變量
var fx = 'fx is a good girl'

function fxFn () {
  console.log(fx)
  var fx = 'fx is a great girl'
  console.log(fx)
  fx = 'very good'
  console.log(fx)
}

console.log(fx)
fxFn()
console.log(fx)

// 依次輸出 1. fx is a good girl 2. undefined 3. fx is a great girl 4. very good 5.fx is a good girl      
var fx = 'fx is a girl'
var fxs = 'yes'

function fxFn () {
  console.log(fx) // undefined
  console.log(fxs) // yes
  fx = 'very good'
  fxs = 'not'
  console.log(fx) // very good
  console.log(fxs) // not
  var fx = 'fx is a great girl'
  console.log(fx) // fx is a great girl
  console.log(fxs) // not
}

console.log(fx) // fx is a girl
console.log(fxs) // yes
fxFn()
console.log(fx) // fx is a girl
console.log(fxs) // not      

什麼是作用域嵌套

當一個塊或函數嵌套在另一個塊或函數中時,就發生了作用域的嵌套。是以,在目前作用域中無法找到某個變量時,引擎就會在外層嵌套的作用域中繼續查找,直到找到該變量,或抵達最外層的作用域(也就是全局作用域)為止。

示例

如下代碼,對 ​

​b​

​​ 進行的 ​

​RHS​

​​ 引用無法在函數 ​

​foo​

​ 内部完成,但可以在上一級作用域(在這個例子中就 是全局作用域)中完成。

function foo (a) {
  console.log(a + b);
}

var b = 2;
foo(2);      

函數被調用之前作用域鍊已經存在

fxAge = 'fx is 18 years old'

function fxFn () {
  console.log(fxAge) // undefined
  var fxAge = 'fx is 8 years old'
  var fxSub = 'fx is 25 years old'
  console.log(fxAge) // fx is 8 years old
  function fxFnSub () {
    console.log(fxSub) // fx is 25 years old
    console.log(fxAge) // fx is 8 years old
  }
  
  return fxFnSub;
}

var fx = fxFn()
fx()      

如下代碼,在函數被執行之前已經建立了兩條作用域鍊:

  • 全局作用域 ->​

    ​fxFn​

    ​ 函數作用域
  • 全局作用域 ->​

    ​fxFnSub​

    ​ 函數作用域
var fx = 'fx is a great girl'

function fxFn () {
  // 輸出的是全局作用域的 fx:fx is a great girl
  console.log(fx)
}

function fxFnSub () {
  var fx = 'fx is 18 years old'
  return fxFn
}

var myFx = fxFnSub()
myFx()      
// x 的作用域是全局作用域,全局作用域中沒有對 a 進行定義
var x = function () {
  console.log(a);
};

function y(f) {
  var a = 2;
  f();
}

y(x) // ReferenceError: a is not defined      

綜上示例,可以了解為

函數的作用域與變量一樣,就是其聲明時所在的作用域,與其運作時所在的作用域無關。

周遊嵌套作用域鍊規則

引擎從目前的執行作用域開始查找變量,如果找不到, 就向上一級繼續查找。當抵達最外層的全局作用域時,無論找到還是沒找到,查找過程都會停止。

作用域鍊

如圖所示,這個建築代表程式中的嵌套作用域鍊。第一層樓代表目前的執行作用域,也就是你所處的位置。建築的頂層代表全局作用域。