1. 程式人生 > >Javascript-基礎概念總結

Javascript-基礎概念總結

塊級作用域 模式 讀取 自己的 同名 作用域鏈 延續 等於 過程

【作用域】
javascript中的作用域可以理解為一個語句執行的環境大小,有全局的作用域,函數作用域和eval作用域。在JS中沒有塊級作用域。
講到作用域,不得不講執行環境,執行環境在JS中是最為重要的概念。執行環境定義了變量或函數有權訪問的其他數據,決定了他們各自的行為。每個執行環境都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象中。在web瀏覽器中全局環境被認為是window對象,某個執行環境中的所有代碼執行完畢後就被該環境銷毀,保存在其中的所有變量和函數定義也隨即銷毀。

每個函數都有自己的執行環境。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行之後,棧將其環境彈出,把控制權返回給之前的執行環境。


當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈。作用域鏈的用途是保證對執行環境有權訪問的所有變量和函數的有序訪問。作用域鏈的前端始終是當前執行的代碼所在環境的變量對象。作用域鏈中的下一個變量對象來自包含(外部)環境,在下一個變量對象則來自於在下一個包含環境,這樣一直延續到全局執行環境,全局執行環境的變量對象始終都是作用域鏈中的最後一個對象。

需註意的是:在局部作用域中定義的變量可以在全局環境和局部環境中交互使用。內部環境可以通過作用域鏈訪問所有的外部環境,但外部環境不可以訪問內部環境中的任何變量和函數。每個環境都可以向上搜索作用域鏈,以查詢變量和函數名,但任何環境都不可以通過向下搜索作用域鏈而進入另一個執行環境。

作用域鏈本質上是一個指向變量對象的指針列表,他只引用但不包含變量對象。

【閉包】
閉包是指有權訪問另一個函數作用域中的變量的函數,這裏要把它與匿名函數區分開(匿名函數:創建一個函數並將它賦值給一個變量,這種情況下創建的函數叫匿名函數,匿名函數的name屬性是空字符串),創建閉包的常見方式就是在一個函數內部創建另一個函數。閉包保存的是整個變量的對象。

閉包的作用:在函數執行過程中,為讀取和寫入變量的值,就需要在作用域鏈中查找變量,這時靈活方便的閉包就派上用場,我們知道當一個函數被調用時就會創建一個執行環境及相應的作用域鏈,那麽閉包就會沿著作用域鏈獲取到開發者想要的變量及元素。

註:在維基百科中是這樣定義閉包的:閉包(也稱詞法閉包或函數閉包)是指一個函數或函數的引用,與一個引用環境綁定在一起。這個引用環境是一個存儲該函數每個非局部變量(也叫自由變量)的表。——閉包不同於一般的函數,它允許一個函數在立即詞法作用域外調用時,仍可訪問非本地變量。

閉包靈活方便,也可以實現封裝,這樣就只能通過對象的特定方法才能訪問到其屬性。但是,不合理的使用閉包會造成空間的浪費,內存的泄露和性能消耗。

【原型和原型鏈】
講到原型鏈,不得不講講用於創建對象的原型模式:我們創建每一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定的所有實例共享的屬性和方法。從字面意思理解,那麽prototype就是通過調用構造函數而創建的那個對象實例的原型對象。使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法。我們可以通過對象實例訪問保存在原型中的值,但卻不能通過對象實例重寫原型中的值。如果我們在實例中添加了一個與原型實例中同名的屬性,那麽我們在實例中創建該屬性,該屬性將會屏蔽原型中的屬性。

無論什麽時候,只要創建一個新函數,就會根據一組特定的規則為函數創建一個prototype(原型)屬性,這個屬性指向函數的原型對象。

原型鏈:用於實現JS中的實現繼承。(許多語言都支持兩種方式的繼承:接口繼承和實現繼承。接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。由於函數沒有簽名,在ECMAScriot中只能實現實現繼承。

原型鏈作為實現繼承的主要方法,其基本思想是利用原型讓一個引用類型繼承另一個引用繼承的屬性和方法。了解一下構造函數、原型和實例的關系:每個構造函數都是一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。假如我們讓原型對象等於另一個類型的實例,那麽此時的原型對象將包含一個指向另一個原型的指針,相應的另一個原型中包含著一個指向另一個構造函數的指針。如此層層遞進,就構成了實例與原型的鏈條。這就是原型鏈的概念。

當函數調用時,需查找和獲取的變量和元素都會通過原型鏈機制一層層的往上搜索在原型對象或繼承來的對象中獲得。

當函數被創建,就有了作用域,當被調用時,就有了作用域鏈,當被繼承時就有了原型鏈,當需要獲取作用域鏈或原型鏈上的變量或值時,就有了閉包。

Javascript-基礎概念總結