1. 程式人生 > >前端之JS(五)

前端之JS(五)

會有 標準 oca 沒有 銷毀 最重要的 集合 return 分析

js的作用域

作用域是JavaScript最重要的概念之一,想要學好JavaScript就需要理解JavaScript作用域和作用域鏈的工作原理。

任何程序設計語言都有作用域的概念,簡單的說,作用域就是變量與函數的可訪問範圍,即作用域控制著變量與函數的可見性和生命周期。在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。

作用域

1. 全局作用域(Global Scope)

在代碼中任何地方都能訪問到的對象擁有全局作用域,一般來說一下幾種情形擁有全局作用域:

(1)最外層函數和在最外層函數外面定義的變量擁有全局作用域

技術分享
var name="yuan";

    function foo(){
        var age=23;
        function inner(){
            console.log(age);
        }

        inner();
    }

    console.log(name);    // yuan
    //console.log(age);   // Uncaught ReferenceError: age is not defined
    foo();                // 23
    inner();              // Uncaught ReferenceError: inner is not defined
技術分享

(2)所有末定義直接賦值的變量自動聲明為擁有全局作用域,例如:

技術分享
    var name="yuan";

    function foo(){
        age=23;

        var sex="male"
    }
    foo();
    console.log(age);   //  23
    console.log(sex);   // sex is not defined
技術分享

變量blog擁有全局作用域,而sex在函數外部無法訪問到。

(3)所有window對象的屬性擁有全局作用域

一般情況下,window對象的內置屬性都都擁有全局作用域,例如window.alert()、window.location、window.top等等。

2. 局部作用域(Local Scope)

和全局作用域相反,局部作用域一般只在固定的代碼片段內可訪問到,最常見的例如函數內部,所有在一些地方也會看到有人把這種作用域成為函數作用域.

如示例1中的age與inner都只有局部作用域。(js中if、for沒有自己的作用域)

作用域鏈(Scope Chain)

在JavaScript中,函數也是對象,實際上,JavaScript裏一切都是對象。函數對象和其它對象一樣,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是[[Scope]],由ECMA-262標準第三版定義,該內部屬性包含了函數被創建的作用域中對象的集合,這個集合被稱為函數的作用域鏈,它決定了哪些數據能被函數訪問。

示例演示

please have a try:

技術分享
//-----**********************例1*********************************

var s=12;
    function f(){
        console.log(s);
         var s=12;          // if s=12
        console.log(s)
    }
    f();

//-----**********************例2*********************************

var s=10;
function foo(){
  console.log(s);
  var s=5;
  console.log(s);
  function s(){console.log("ok")}// 函數的定於或聲明是在詞法分析時完成的,執行時已不再有任何操作

  console.log(s);
}

foo();

//-----***********************例3********************************

function bar(age) {

        console.log(age);
        var age = 99;
var sex= ‘male‘; console.log(age); function age() {
alert(123) }; console.log(age);
return 100; } result=bar(5); //-----********************************************************
技術分享

結果分析

我相信大家一定會有想不到的結果,接下來我們就以最復雜的例3來分析整個過程。

當一個函數創建後,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。在函數bar創建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,如下圖所示:

技術分享

解析到函數調用時,即bar(5),會生成一個active object的對象,該對象包含了函數的所有局部變量、命名參數、參數集合以及this,然後此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對象也隨之銷毀。新的作用域鏈如下圖所示:

技術分享

過程解析:

技術分享
function bar(age) {

        console.log(age);
        var age = 99;
        var sex="male";
        console.log(age);
        function age(){
            alert(123);
        } ;
        console.log(age);
        return 100;
}

result=bar(5);

一 詞法分析過程(涉及參數,局部變量聲明,函數聲明表達式):
    1-1 、分析參數,有一個參數,形成一個 AO.age=undefine;
    1-2 、接收參數 AO.age=5;
    1-3 、分析變量聲明,有一個 var age, 發現 AO 上面有一個 AO.age ,則不做任何處理
    1-4 、分析變量聲明,有一個 var sex,形成一個 AO.sex=undefine;
    1-5 、分析函數聲明,有一個 function age(){} 聲明, 則把原有的 age 覆蓋成 AO.age=function(){};
二 執行過程:
    2-1 、執行第一個 console.log(age) 時,當前的 AO.age 是一個函數,所以輸出的一個函數
    2-2 、這句 var age=99; 是對不 AO.age 的屬性賦值, AO.age=99 ,所以在第二個輸出的age是 99;
    2-3 、同理第三個輸出的是 99, 因為中間沒有改變 age 值的語句了。

          註意:執行階段:
                        function age(){
                            alert(123)
                        } ;

            不進行任何操作,將執行語句復制給age這部操作是在詞法分析時,即運行前完成的。
技術分享

前端之JS(五)