摘要:執行環境對象和作用域鏈執行環境,又稱執行上下文,是指一個函數在執行的時候所能直接引用的變量等的一個集合。為了解釋作用域鏈的機制,我們再來引入一個屬性的概念。而函數的執行環境對象作用域鏈保存了函數在執行時能解析到的變量。
執行環境對象和作用域鏈
執行環境,又稱執行上下文,是指一個函數在執行的時候所能直接引用的變量等的一個集合。
在JavaScript引擎中,執行環境是由一類特殊的對象——執行環境對象——來實現的。由于一個函數執行的時候可能對應不同的上下文,所以每次函數執行的時候都會由引擎為該函數創建一個獨一無二的執行環境對象。函數執行完畢時,由垃圾回收(GC)機制來決定是否將該執行環境對象回收。
為了區別執行環境和執行上下文,我將下文中的執行環境稱作“執行上下文”。
注意:全局環境(全局作用域所在的環境)雖然不是一個函數,但是其中的代碼執行時,也會有一個相應的執行環境對象與之對應。
不同執行環境中的變量是存在依賴關系的。
例如:一個全局執行環境下創建的函數在執行時,其執行環境需要知道全局執行環境中的變量:window、document、以及其他聲明的全局變量(注意:未聲明的變量作為window對象的屬性,和聲明過的全局變量有略微的不同之處)。熟悉函數作用域概念的同學,不難理解這種依賴關系。
這種依賴關系是通過執行環境對象中的一個特殊的屬性,引用創建該函數時的所對應的執行環境對象來實現的。由于這種引用關系可以形成一條引用鏈,一個函數執行時,引擎對變量的解析就是通過對執行環境對象引用鏈的遍歷來解析確定的。
這個引用鏈有個高大上的、經常聽到的名字——作用域鏈。
為了解釋作用域鏈的機制,我們再來引入一個scope屬性的概念。
函數對象的scope屬性我們知道,JavaScript的函數是Function構造函數的實例,本質是一類特殊的對象。某一個對象只可能在某一個獨一無二的執行上下文中創建,但是函數對象會在不同的執行上下文中執行。
函數對象有很多屬性,其中一個就是只有在JavaScript引擎中可見的scope屬性。這個scope屬性指向創建該函數時對應的執行環境對象。
該函數執行的時候,使用函數內的函數作用域變量創建一個新執行環境對象,并且引用scope屬性指向的執行環境對象。這個執行環境對象和該函數的執行上下文相對應。
這三者對應關系如下圖所示:
但是scope屬性依然引用創建這個函數的執行環境對象,原因跟上面的解釋是一樣的:
函數執行時變量解析一個函數只能在某個特定的執行上下文中創建,但是會在不同的執行上下文中執行。
從作用域鏈的角度解釋:首先從該函數所對應的執行環境對象中搜索該變量,如果沒有則沿著作用域鏈繼續搜索,直到找到為止。然后將數據取出或者存儲。
這里有一個優化問題:不要在代碼中過多的引用作用域鏈中離頭結點(即當前執行環境對象)較遠的結點中的變量。解決辦法:將這個非頭結點中的變量賦值給函數局部變量變為頭結點中的變量,這樣就不需要每次都去搜索作用域鏈了。
題外話:thisthis可以認為是一個特殊的變量,代表函數的調用者。每一個執行環境對象中都有一個this,但是變量搜索時,只需搜索當前的執行環境對象就可以找到這個變量。當需要找到作用域鏈中非頭結點的this時,需要將其保存為其他特定的能被引用到的局部變量來處理。
閉包現在我們可以看看小宇宙中的黑魔法了。
函數B在函數A中被返回。那么創建函數B的執行環境對象就是函數A對應的執行環境對象。那么函數B的scope對象會保存函數A的執行環境對象。
而函數A的執行環境對象作用域鏈保存了函數A在執行時能解析到的變量。所以函數B中就能通過其scope屬性訪問函數A的執行環境中的變量。
假設函數B的調用者無法訪問函數A中的變量,那么它只能通過函數B的行為來獲得函數A中的變量狀態。
此時函數B由于其scope屬性保存了函數A的執行環境對象的作用域鏈,從而形成一個閉包。
結束一點微小的見解。
本文涉及JavaScript界的敏感話題,故而,如有紕漏,歡迎吐槽。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90860.html
摘要:本期推薦文章從作用域鏈談閉包,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。推薦理由這是一篇譯文,深入淺出圖解作用域鏈,一步步深入介紹閉包。作用域鏈的頂端是全局對象,在全局環境中定義的變量就會綁定到全局對象中。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周開始前端進階的第二期,本周的主題是作用域閉包,今天是第6天。 本...
摘要:變量對象也是有父作用域的。作用域鏈的頂端是全局對象。當函數被調用的時候,作用域鏈就會包含多個作用域對象。當函數要訪問時,沒有找到,于是沿著作用域鏈向上查找,在的作用域找到了對應的標示符,就會修改的值。 一、概要 對于閉包的定義(紅寶書P178):閉包就是指有權訪問另外一個函數的作用域中的變量的函數。 關鍵點: 1、閉包是一個函數 2、能夠訪問另外一個函數作用域中的變量 二、閉包特性 對...
摘要:閉包面試題解由于作用域鏈機制的影響,閉包只能取得內部函數的最后一個值,這引起的一個副作用就是如果內部函數在一個循環中,那么變量的值始終為最后一個值。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第8天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數,也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:前言這段時間一直在消化作用域鏈和閉包的相關知識。而作用域鏈則是這套規則這套規則的具體運行。是變量對象的縮寫那這樣放有什么好處呢我們知道作用域鏈保證了當前執行環境對符合訪問權限的變量和函數的有序訪問。 前言:這段時間一直在消化作用域鏈和閉包的相關知識。之前看《JS高程》和一些技術博客,對于這些概念的論述多多少少不太清楚或者不太完整,包括一些大神的技術文章。這也給我的學習上造成了一些困惑,...
閱讀 3794·2023-04-25 16:32
閱讀 2194·2021-09-28 09:36
閱讀 2034·2021-09-06 15:02
閱讀 673·2021-09-02 15:21
閱讀 918·2019-08-30 15:56
閱讀 3513·2019-08-30 15:45
閱讀 1708·2019-08-30 13:09
閱讀 379·2019-08-29 16:05