介紹下作用域鏈

介紹一下JavaScript作用域鏈?

  1. 什么是作用域鏈
  • 每個函數都有自己的 執(zhí)行環(huán)境 ,當執(zhí)行流執(zhí)行到一個函數時,函數的環(huán)境就會被推入到一個 環(huán)境棧 中,而在函數執(zhí)行之后,棧將其環(huán)境彈出,將控制權返給之前的執(zhí)行環(huán)境;
  • 當代碼在一個環(huán)境中訪問時,會創(chuàng)建變量對象的一個 作用域鏈 。作用域鏈的用途,就是 保證對執(zhí)行環(huán)境有權訪問的所有變量和函數的有序訪問 ;作用域鏈的前端,始終都是 當前執(zhí)行代碼所在環(huán)境的變量對象 。如果這個變量是函數,則將其活動對象作為變量對象;活動對象在最開始時只包含一個變量,即argumnets對象(這個對象在全局環(huán)境中是不存在的)。作用域鏈中的下一個變量對象來自包含環(huán)境,在下一個變量對象則來自再下一個包含環(huán)境。這樣,一直延續(xù)到 全局執(zhí)行環(huán)境。全局執(zhí)行環(huán)境始終是作用域鏈中的最后一個對象。

const color = 'red'
const function = sayColor(){
  const innerColor = 'blue'
  console.log(color)
}
sayColor()  // 'red'

  • 在上面的例子中,sayColor()的作用域鏈中包含兩個變量對象,他自己的活動對象(其中包含著argumnets對象)和全局環(huán)境的變量對象
  • 可以在函數內部訪問到變量color,就是因為可以在這個作用域鏈中找到他;
  • 內部環(huán)境可以通過作用域鏈訪問所有的外部環(huán)境,但是外部環(huán)境不能訪問內部環(huán)境的任何變量和函數;這些環(huán)境之間的聯(lián)系是線性的,有次序的,每個環(huán)境都可以向上搜索作用域鏈,以查詢變量和函數名; 但是任何環(huán)境都不能向下搜索作用域鏈而進入另一個執(zhí)行環(huán)境;
  1. 延長作用域鏈
  • 雖然執(zhí)行環(huán)境的類型只有兩種,全局和局部(函數),但還是有其他方法來延長作用域鏈,這么說是因為,可以通過一些手段,在作用域鏈的前端,臨時增加一個變量對象,這個變量對象會在代碼執(zhí)行之后被移除。這兩種情況下會發(fā)生這種現象,具體來說,當執(zhí)行流進行到下面任何一個語句時,作用域鏈就會得到加長;
    • try-catch語句的catch塊
    • with語句
  • 這兩個方法都會在作用域鏈的前端增加一個變量對象。對with語句來說,會將指定的對象添加到作用域鏈中。對ctach語句來說,會創(chuàng)建一個新的變量對象,其中包含的是被拋出的錯誤對象的變量聲明;
function basicUrl(){
  var qs = 'haha';
  with(location){
    return url = href + qs
  }
  return url;
}
basicUrl()
// "http://localhost:4000/Blog/haha"
  • 在此,with 語句接收的是location對象,因此其變量對象中包含了location的所有屬性和方法,而這個變量對象被添加到了作用域鏈的前端。basicUrl()函數中定義了一個變量qs,當在with語句中引用變量href時(實際引用的是location.href),可以在當前執(zhí)行環(huán)境的變量對象中找到;當引用變量qs時,引用的則是basicUrl中定義的 qs,而該變量位于函數環(huán)境的變量對象中。至于with語句內部,則定義了一個名為url的變量,因此url就成為了函數執(zhí)行環(huán)境的一部分,所以可以作為函數的值被返回。
function compare(value1, value2) {
  if (value1 > value2) {
    return 1;
  } else if (value1 < value2) {
    return -1;
  } else {
    return 0;
  }
}
const result = compare(2, 3);

  • 全局環(huán)境的變量對象始終存在,而象compare()函數這樣的局部環(huán)境的變量對象,僅在函數執(zhí)行的過程中存在。在創(chuàng)建compare()函數時,會創(chuàng)建一個預先包含全局變量對象的作用域鏈,這個作用域鏈被保存在內部的 [[Scope]] 屬性中。當調用compare()函數時,回味函數創(chuàng)建一個執(zhí)行環(huán)境,然后通過復制 [[Scope]] 屬性中的對象,構建起執(zhí)行環(huán)境的作用域鏈。此后,又有一個活動對象(在此作為變量對象使用)被推入執(zhí)行環(huán)境作用域鏈的前端。
  • 對于這個例子中的compare()函數的執(zhí)行環(huán)境而言,其作用域鏈包含兩個變量對象,本地活動對象和全局變量對象。
  • 作用域鏈本質上是一個指向變量對象的指針列表,他只引用但不實際包含變量對象
  • 無論什么時候在函數中搜索一個變量時,就會從作用域鏈中搜索具有相應名字的變量,一般來講,當函數執(zhí)行完畢后,局部活動對象就會被銷毀,內存中僅保存全局作用域(全局環(huán)境的活動對象),但是閉包的情況有所不同
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容