JavaScript函數之作用域 / 作用鏈域 / 預解析


關於作用域和作用鏈域的問題,很多文章講的都很詳細,本文屬於摘錄自己覺得對自己有價值的部分,留由后用,僅供參考,需要查看詳細信息請點擊我給出的原文鏈接查看原文件

做一個有愛的搬運工~~

-------------------------------------------------------------------------------------------------------------------------------------------

作用域

js中作用域只有一種,就是函數作用域,除此之外,還存在一種作用域叫塊作用域,但在此之前,想先說一下什么叫做塊

  

  在JAVA或者C中(因為我只學過這兩種語言),塊就是寫在{}中的語句,一般看作一條語句執行,

  塊作用域(JS中不存在塊作用域的概念)

  在塊中的語句對塊外是封閉的,在JAVA和C中都有這樣的特性

  例如

//JAVA 代碼
public class Block {
    public static void main(String[] args) {
        if(true){
            int i = 9;
        }
        System.out.println(i);//代碼報錯
    }
}
//以上的代碼編譯時會報錯,強制編譯並執行時會拋出以下的錯誤:
//Exception in thread "main" java.lang.Error: Unresolved //compilation problem: i cannot be resolved to a variable

  所以,JAVA是有塊作用域的概念的,同樣的代碼,放在JS中時

//JavaScript代碼
function fun(){
        if(true){
                var i = 9;
        }
        return i;
}
fun();//輸出 9

  這就說明, 在if語句中聲明的變量在if語句之后被保留在內存中了,並沒有銷毀.

  需要特別說明的是:JS中,在函數中用var定義的變量是局部變量,不用var定義的變量會默認作為全局變量使用

function f1(){
        var n=9;
        m = 10;  
}
f1();
console.log(n);//不會輸出結果,報錯誤:ReferenceError: n is not defined, 意思是該變量未定義
console.log(m);//輸出10

  關於這個說法,在很多文章中都有提及,比如 Javascript中模仿塊級作用域  : 其中對JS中作用域的解釋說:使用var關鍵字聲明變量時,這個變量會自動添加到距離最近的可用環境中。對於函數而言,這個最近的環境就是函數的局部環境。如果變量在未經聲明的情況下被初始化,則該變量會被自動添加到全局環境。

 

在JS中實現塊作用域的使用效果

同樣在  Javascript中模仿塊級作用域 這篇文章中,利用匿名函數來實現塊作用域的功能

 

(function(){

    //塊級作用域

})();
//來自原文的話: 這種技術常在全局作用域中用在函數外部,來限制向全局作用域中添加過多的變量和函數。當然,只要我們臨時需要一些變量,都可以使用塊級作用域(私有作用域)。當匿名函數執行完畢,其作用域鏈立即銷毀,從而可以減少閉包占用資源問題。

  在這里再貼一個也比較好的說明作用域知識的文章 js作用域問題一步步透徹理解

  這篇文章中,有這樣一個例子(這個細節是我之前並沒有注意過的>>細節指數:★★★★)

function fun(){
        var a = b = 10;
}
console.log(a);//ReferenceError: a is not defined
console.log(b);//輸出: 10
/*
 *原文的話:  var a = b = 10; 這種寫法在函數內: b其實是全局變量,a當然是局部變量 */

  所以我自己給出了下面的例子

function fun(){
        var a = 10, b = 10;
}
console.log(a);//ReferenceError: a is not defined
console.log(b);//ReferenceError: b is not defined
/*
 *a是局部變量
 *b是局部變量
 *我們可以很清楚的知道, var a = 10, b = 10; 這種寫法在函數內是定義局部變量的有效方法,
 */

-----------------------------------------------------------------------------------------------------------------------

作用鏈域

  預解析(在說作用鏈域之前,我想先說一個問題---預解析,先給出引用的文章地址, 方便回溯)

  解釋一下啥叫預解析(自己起的名),希望給一些初學js的提供些幫助

  說法:js引擎讀取一段js代碼,首先預解析(這個名字我起的),就是逐行讀取js代碼,尋找全局變量和全局函數,遇到全局變量,把變量的值變為undefind,存在內存中,遇到全局函數,直接存在內存中,這個過程如果發現語法錯誤,預解析終止。

  當預解析完成后,js引擎在從第一行開始逐行運行js代碼。

  js的預解析

  說法:js的預解析是在程序進入一個新的環境時,把該環境里的變量或函數預解析到它們能調用的環境中。即每一次預解析的單位是一個執行環境。

  轉:javascript(js)預解析原理

  說法:函數預解析

  1、javascript在執行前會進行類似“預解析”的操作:首先會創建一個在當前執行環境下的活動對象,並將那些用var 聲明的變量、定義的函數設置為活動對象的屬性,但是此時這些變量的賦值都是undefined。

  2、在javascript解釋執行階段,遇到變量需要解析時,會首先從當前執行環境的活動對象中查找,如果沒有找到‍而且該執行環境的擁有者有prototype屬性時則會從prototype鏈中查找,否則將會按照作用域鏈查找。遇到var a = …這樣的語句時會給相應的變量進行賦值(注意:變量的賦值是在解釋執行階段完成的,如果在這之前使用變量,它的值會是undefined)。

 

//預處理的例子

console.log(a);//輸出: undefined
console.log(b);//輸出: undefined
console.log(c);//輸出: function c(){return "C";}

var a = "A";
var b = function(){return "B"; }
function c(){return "C";}

//在語法分析階段,a保存用var進行顯示聲明的局部變量,並且置默認值為undefined,這里就是上述代碼中"console.log(a)"輸出為undefined的原因,由於代碼在語法分析階段就已經保留了標記符a,在賦值語句"var a = "A"; "執行之前a的值都是undefined,因此在"console.log(a)"的時候就顯示為undefined了。(修改引用自:(轉載)淺談JavaScript的閉包和作用域鏈)

 

 

  至此,如果預解析的概念有所了解了(其實我還沒有完全理解,疑問就是:上例中的b和c的輸出結果為什么不一樣???如果有人理解,可以評論告訴我,不勝感激),就可以來說說作用鏈域的事兒了.

  作用鏈域

  看看這篇文章:  (轉載)淺談JavaScript的閉包和作用域鏈(這篇文章講了很多機制性的東西,個人覺得比較好!!!)

  原文:作用域鏈(scope chain)就是由作用域組成的鏈,是一個類似鏈狀的數據結構。作用域就是對上下文環境的數據描述。閉包和作用域鏈是緊密關系的,函數實例執行時的閉包是構成作用域鏈的基本元素。JavaScript代碼在執行前會進行語法分析,在語法分析階段,會記錄全局環境中的變量聲明和函數定義,構造函數的調用對象(Call Oject、Activation Object、Activate Object、活動對象,不同稱呼罷了)和在全局環境下的作用域鏈。

  [  關於閉包的內容我會在下一篇文章  JavaScript函數之閉包  中具體來說  ]

  至於作用鏈域的其他知識點,我感覺沒有辦法總結的比文章(轉載)淺談JavaScript的閉包和作用域鏈要好,所以,不多說,看原文!

--------------------------------------------------------------------------------------------------------------------------

參考文章:

Javascript中模仿塊級作用域

js作用域問題一步步透徹理解

解釋一下啥叫預解析(自己起的名),希望給一些初學js的提供些幫助

js的預解析

轉:javascript(js)預解析原理

(轉載)淺談JavaScript的閉包和作用域鏈


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM