原型模式故事鏈(4)--JS執行上下文、變量提高、函數聲明

上一章:JS的數據類型 傳送門:https://segmentfault.com/a/11...javascript

好!話很少少,咱們就開始吧。對變量提高和函數聲明的理解,能讓你更清楚容易的理解,爲何你的程序報錯了~哈哈哈css

咱們前端的代碼通常就三個部分組成html + css +js,通常呢咱們的JS又會放在最後執行。html

執行上下文:
所謂的執行上下文,就是JS代碼執行的環境。前端

Javascript中代碼的運行環境分爲如下三種:java

全局上下文 - 這個是默認的代碼運行環境,一旦代碼被載入,引擎最早進入的就是這個環境。segmentfault

函數上下文 - 當執行一個函數時,運行函數體中的代碼。閉包

Eval上下文 - 在Eval函數內運行的代碼。函數

這個和做用域有點像。
每次調用一個函數將會建立一個新的執行上下文會,被添加到做用域鏈的頂部。
做用域和執行上下文之間最大的區別是: 執行上下文在運行時肯定,隨時可能改變;做用域在定義時肯定,永遠不會改變。學習

其實上面那些看看就好,直接看代碼吧。this

JS代碼在執行以前會先全局中變量提高、函數聲明。在函數中變量提高、函數聲明(this、函數參數也會提高,函數中的變量提高的範圍是這個函數的內部)

變量提高:變量賦值的過程:聲明---初始化---賦值
舉例子:函數內部的變量提高(全局的變量提高也是同理)

function fn(){
        console.log(x);//undefined
        var x = 1;
        console.log(x);//1
    }
    fn();

這裏咱們從針對變量x來解說:
1.在執行fn時,爲fn建立一個執行環境。(fn函數的執行上下文,也就是在fn這個函數範圍內)
2.找到fn函數執行上下文中(fn函數範圍內),全部用var聲明的變量。
3.將這些變量初始化爲undefined。
4.開始執行代碼。
5.把1賦值給變量x。

至關於以下這樣:

function fn(){
        //把用var聲明的變量,提高到頂部,並初始化爲undefined
        var x =undefined;
        
        //開始執行代碼。
        console.log(x);//undefined
        //把1賦值給變量x。
        var x = 1;
        console.log(x);//1
    }
    fn();

函數聲明:

cat();//123
    function cat(){
        console.log(123);
    }
    cat();//123

1.找到全部用function聲明的變量,並在環境中建立這些變量。
2.將這些變量初始化並賦值爲function(){xxx}
3.在環境中從上往下開始執行代碼。

至關於以下這樣:

//1.找到全部用function聲明的變量,並在環境中建立這些變量。
    //2.將這些變量初始化並賦值爲function(){xxx}
    var cat = function (){
        console.log(123);
    }
    //3.在環境中從上往下開始執行代碼。
    cat();//123
    cat();//123

這個就是函數聲明,在代碼執行前,會把function提到頂部。因此若是不行代碼,代碼塊裏即便有錯誤也不會報出來,只有執行時纔會運行代碼內部東西。

看到這裏應該有個初步瞭解了,那麼來看看下面的。加點難度,加深瞭解。

<!DOCTYPE html>
<html>
<head>
    <title>3543541</title>
</head>
<body>
<script type="text/javascript">
    
    fn2();//undefined
    fn();//undefined

    function fn(){
        console.log(g);
    }
    fn();//undefined

    console.log(g);//undefined
    var g = 'global';
    console.log(g);//global

    fn2()//global
    function fn2(){
        console.log(g);
    }
    fn2()//global
    fn();//global
</script>
</body>
</html>

爲何fn中的globle拿不到呢?而fn2的globle能拿到值呢?
運用上面學習的知識來分析一波。
上面代碼在執行前,會通過變量提高、函數聲明,因此在準備執行前的代碼是這樣的:

//函數聲明會在最最頂端
    var fn = function (){
        console.log(g);
    }
    var fn2 = function (){
        console.log(g);
    }
    //執行函數和變量按照相對位置排列
    //執行的相對位置不能變,這3個是在變量g以前執行的就要一直在g以前執行
    fn2();
    fn();
    fn();

    var g = undefined;
    console.log(g);//undefined
    var g = 'global';
    console.log(g);//global

    //執行的相對位置不能變,這3個是在變量g以後執行的就要一直在g以後執行
    fn2();
    fn2();
    fn();

這裏咱們能夠總結出一點規律:
1.函數聲明會在最最頂端
2.變量提高,只是在本身的範圍內提高
3.執行的相對位置不能變和變量按照執行上下文以前的相對位置排列。
4.函數執行時,按照執行位置查找變量做用域只會向上查找。

下一回:變量做用域與閉包

相關文章
相關標籤/搜索