如何延長作用域鏈 重溫JS中的執行環境和作用域鏈

2021-10-11 17:17:57 字數 2033 閱讀 5152

說明:以下**說明和原理都是基於es5和非嚴格模式進行

執行環境定義了變數或函式有權訪問的其他資料。每個執行環境都有與之關聯的變數物件,一般情況下我們無法訪問變數物件,解析器會在我們訪問變數或函式時在後台使用它。

執行環境的所有**執行完畢後,該環境被銷毀,其中的變數和函式定義被銷毀。web瀏覽器的全域性執行環境是window物件,所有的全域性變數和函式,都是window的屬性和方法,全域性執行環境會在程式退出時才會銷毀,也就是關閉網頁或者瀏覽器關閉的時候。

**在任何環境執行中都會生成乙個作用域鏈,它可以保證當前環境下變數和函式的有序訪問。作用域的前端始終是當前執行環境的變數物件,簡單的說,就是變數搜尋從當前執行環境向上搜尋。

函式的變數物件是他的活動物件,最開始也就是arguments物件。作用域鏈的下乙個變數物件來自外部包含環境,再下乙個來自下乙個包含環境,直到全域性執行環境,也就是說全域性執行環境是作用域鏈的末端。

var color = 'blue'function changecolor ()  // 這裡可以訪問color anothercolor swapcolors()}// 這裡只能訪問colorchangecolor()

圖中矩形為執行環境,內部環境可以通過作用域鏈訪問所有的外部環境,反之不行。每個執行環境都向上搜尋作用域鏈來查詢變數和函式。所以swapcolors包含三個變數物件,自己的,changecolor的,window的,changecolor只包含兩個,自己的和window。

所以,作用域只能按照順序向上搜尋變數。

ps:函式引數也是變數。規則和普通宣告變數一致。

執行環境只用全域性和區域性兩種,但還是有辦法在作用域前端新增乙個變數物件,典型的例子有:

try。。。catch。。。語句

with語句

try  catch (e)console.log(a) // 123console.log(e) // 報錯,說明訪問不到e變數,所以try和catch不在乙個作用域。// 這裡的catch語句延長了作用域鏈,所以catch語句中,向上訪問到了a變數。// 最後的兩個列印說明了catch的確是延長了作用域鏈所以才能訪問到a。function buildurl ()  console.log(url) // 有結果}// with 會把指定的物件新增到作用域鏈前端,所以,訪問href時,直接就在當前環境中找到。而不會向上了。
也就是{}無法形成封閉的作用域。

if (true) console.log(color); // 'blue'
宣告變數如果初始化變數時沒有使用var等關鍵字宣告,那麼將會是全域性變數。

function add(num1, num2) add(1,2)console.log(sum) // 3// 所以在初始化變數時必須宣告。
查詢標示符前面已經說過,變數查詢是沿著作用域鏈向上找,找到的第乙個變數作為結果返回。所以作用域鏈上存在同名變數時會存在變數遮蔽。

var name = 'foo'function bar () bar() // 'bar'
var name = 'window' function foo () }var bar = foo() // 執行這一句時,因為返回了乙個方法,方法是乙個引用物件,導致foo方法執行完成後,沒辦法// 銷毀它自身執行環境中的變數(因為無法**方法的引用)。// 既然無法銷毀執行環境那麼作用域鏈就不會消失,當執行bar方法時就會沿著最開始的作用域鏈向上查詢。bar() // 'foo' 可以訪問到foo中的變數。(所以這裡不是window)

js延長作用域鏈

雖然執行環境的型別只有全域性函式和區域性函式,但還是有其他辦法來延長作用域的。實現的原理是有些一句可以在作用域的前端臨時加乙個變數物件,該變數物件會在 執行後被移除。有兩種情況可以達到這種效果 try catch語句的catch塊 with語句 上面兩個語句都會在作用域的前端新增乙個變數物件。對wi...

JS中的作用域鏈

在js中資料的宣告方式有兩種 1 用var宣告,例如 var num 10 2 直接宣告,例如 num 10 兩種宣告方式在某些情況下是有區別的 var data 10 function fn01 fn03 fn02 fn01 console.log data 此時data會是多少呢?沒錯就是10 ...

JS函式作用域延長的方法

當 在乙個環境中執行時,會建立變數物件的乙個 作用域鏈 scope chain 作用域鏈的用途,是保證對執行環境有權訪問的所有變數和函式的有序訪問。作用域鏈的前端,始終都是當前執行的 所在環境的變數物件。如果這個環境是函式,則將其 活動物件 activation object 作為變數物件。活動物件...