JS面向對象之作用域


作用域

詞法作用域

作用域

表示的就是范圍,即作用范圍

  • 就是一個名字在什么地方能使用,在什么地方不能使用

塊級作用域

級別的作用范圍

    // 在 c , java 等編程語言中,下面的語法報錯
    {
        var num = 123;  // 應該用int , 這里是偽代碼
        {
            console.log(num);   // 123
        }
        console.log(num);   // 報錯
    }

在 js 中采取詞法作用域

詞法(代碼)作用域,就是代碼在編寫過程中體現出來的作用范圍,代碼一旦寫好,不用執行,他的作用范圍就已經確定好了,這個就是所謂的詞法作用域
在 js 中的詞法作用域規則
1. 函數允許方位函數外的數據
2. 整個代碼結構中只有函數可以限定作用域
3. 作用規則首先是提升規則分析
4. 就近原則如果當前作用規則有了名字,就不考慮外面的名字

在 js 中作用域分析方法

1. 先進行預解析,分析預解析過程
    * 程序在執行過程, 會先將代碼讀取到內存中檢查. 會將所有的聲明在此時進行標記. 所謂的標記就是
讓 js 解釋器知道有這個名字, 后面在使用名字的時候, 不會出現未定義的錯誤. 這個標記過程就是提升.
    * 聲明
    1. 名字的聲明, 標識符的聲明( 變量名聲明 )
    	* 名字的聲明就是讓我們的解釋器知道有這個名字
    	* 名字沒有任何數據與之對應
    2. 函數的聲明
    	* 函數聲明包含兩部分
    	* 函數聲明與函數表達式有區別, 函數聲明是單獨寫在一個結構中, 不存在任何語句, 邏輯判斷等結構中
    	* 首先函數聲明告訴解釋器有這個名字存在. 該階段與名字聲明一樣
    	* 告訴解釋器, 這個名字對應的函數體是什么**(函數名和函數體綁定鏈接)**
2. 再進行代碼執行過程

常見的簡單作用域問題

例子 1:

    var num = 123;
    function foo(){
        console.log(num);
    }
    foo();  // 輸出 123

分析

  1. 預解析
   變量num變量名提升
   函數foo函數名提升
  1. 代碼執行
   num賦值123,函數內區域為獨立區域,可以使用外部數據,但是現在變量名相同,覆蓋外面的值
   函數foo執行
   函數區域中變量num變量名提升
   輸出num 為undefined
   num賦值456
   輸出num 為456

例子 2:

    if(false){
        var num = 123;
    }
    console.log(num);   // 輸出undefined

分析

  1. 預解析
   變量名num提升
  1. 執行代碼
   if判斷為false,不進入
   輸出num,num定義未賦值,為undefined

例子 3:

    var num = 123;
    function foo(){
        var num = 456;
        function fn(){
            console.log(num);   //  輸出456
        };
        fn();
    }
    foo();

分析

  1. 預解析
   變量名num和函數名foo聲明提升,函數名foo和函數體鏈接
  1. 執行代碼
   num = 123, 賦值
   執行函數, 函數內部聲明提升,變量名num和函數名fn
   變量num=456, 執行函數fn
   輸出num, fn函數內部沒有num,向上級尋找
   num=456, 輸出num

例子 4:

    var num = 123;
    function foo1(){
        var num = 456;
        function foo2(){
            num = 789;
            function foo3(){
                console.log(num);   // 輸出789
            }
            foo3();
        }
        foo2();
    }
    foo1();     // 輸出456
    console.log(num);   // 輸出123

分析

  1. 預解析
   變量名num和函數名foo1聲明提升,函數名foo1和函數體綁定
  1. 執行代碼
  num = 123, 賦值
   執行函數foo1, 變量名num和函數名foo2聲明提升, 函數名foo2和函數體綁定
   num = 456, 賦值
   執行函數foo2, num在foo2函數中沒有, 訪問上級foo1得到num,  num = 789, 賦值函數名foo3聲明提升並且綁定函數體
   執行函數foo3, 輸出num, foo3中沒有num,訪問上級,得到num = 789
   輸出num為789
   跳出函數, 輸出num為123

例子 5:

    if ( ! 'a' in window ) {
        var a = 123;
    }
    console.log( a );   // undefined

分析

  1. 預解析
   變量a聲明提升
  1. 執行代碼
   判斷window中是否存在a,a存在
   判斷為false,不執行if中的代碼
   輸出a,為undefined

復雜的作用域問題

例子 1

    if ( true ) {
        function f1 () {
            console.log( 'true' );
        }
    } else {
        function f1 () {
            console.log( 'false' );
        }
    }
    f1();

分析
新版瀏覽器

  1. 預解析
   無,函數f1被瀏覽器認為是函數表達式,不進行變量名提升
  1. 執行代碼
   if判斷進入true
   執行函數表達式f1
   輸出結果為true

舊版瀏覽器

  1. 預解析
   函數f1變量聲明提升,f1函數名和最后一個函數體連接在一起
  1. 執行代碼
   if判斷進入true
   執行f1
   輸出false

例子 2

    if ( false ) {
        function f1 () {
            console.log( 'true' );
        }
    } else {
        function f1 () {
            console.log( 'false' );
        }
    }
    f1();

分析
新版瀏覽器

  1. 預解析
   無,f1為函數表達式,沒有進行聲明提升
  1. 執行代碼
   if判斷
   執行f1
   輸出false

舊版瀏覽器

  1. 預解析
   函數名f1,聲明提升,函數名和最后一個函數體鏈接在一起
  1. 執行代碼
   if判斷
   執行f1
   輸出false

例子 3

    var num = 123;
    function f1() {
        console.log( num );
    }
    function f2() {
        var num = 456;
        f1();
    }
    f2();

分析

  1. 預解析
   聲明提升,變量num,函數名f1,f2,函數名和函數體鏈接
  1. 執行代碼
   num = 123
   執行函數f2
   變量num賦值456
   執行函數f1
   輸出num,函數里面沒有,向上尋找,上級為(0級作用域鏈),num=123,輸出num為123

例子 4

    var num = 123;
    function f1() {
        console.log( num );
    }
    function f2() {
        num = 456;
        f1(num);
    }
    f2();

分析

  1. 預解析
 變量名num,函數名f1,f2聲明提升,函數名和函數體鏈接一起
  1. 代碼執行
 num=123
 執行函數f2
 num=456,f2中沒有num,向上級尋找得到num為123,將num = 123賦值,num = 456
 執行f1, f1中沒有num, 向上級尋找得到num為456
 輸出num,num=456,輸出num456


免責聲明!

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



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