首頁  >  文章  >  web前端  >  深入Javascript函數、遞迴與閉包(執行環境、變數物件與作用域鏈)使用詳解_基礎知識

深入Javascript函數、遞迴與閉包(執行環境、變數物件與作用域鏈)使用詳解_基礎知識

WBOY
WBOY原創
2016-05-16 17:34:15894瀏覽

函數表達式

1、JavaScript中定義函數有2鐘方法:

  1-1.函數宣告:

複製程式碼



複製程式碼

程式碼>
function funcName(arg1,arg2,arg3){  //函數體

}
    ①name屬性:可讀取函數名稱。非標準,瀏覽器支援:FF、Chrome、safari、Opera。

    ②函數宣告提升:指執行程式碼之前會先讀取函數宣告。即函數呼叫可置於函數宣告之前。   1-2.函數表達式:

複製程式碼


複製程式碼



複製程式碼

    ① ):function關鍵字後無標識符,name屬性值為空字串。在把函數當成值使用時,都可用匿名函數。     ②類似其他表達式,函數表達式使用前需先賦值,故不存在"函數宣告提升"那樣的作用。

    ③ECMAScript中的無效函數語法:




複製程式碼


程式碼中的重複函數宣告

if(condition){
    function sayHi(){
        alert("Hi!");
      alert( "Yo!");

複製代碼



代碼如下:


if判斷函數表達式

var sayHi;
if(condition){
    sayHi = function(){
        alert("Hi!"); (){

        alert("Yo!");
    }}

2、遞歸函數2、遞歸函數
2、遞歸中透過名字調用自身的情況下構成的。




複製程式碼


程式碼如下:


function factorial(num){ 階乘函數
    if (num         return 1;    } else {      ①若使用下列程式碼呼叫函數,會發生錯誤:



複製程式碼


複製程式碼
複製程式碼var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4));

 , factorial變數設為null後不再引用函數,而anotherFactorial(4)中要執行factorial()函數,故出錯。
      使用argument.callee(指向正在執行的函數的指標)可解決:




複製程式碼



複製程式碼

複製程式碼複製碼>解決方案 function factorial(num){    if (num         return 1;    } else { 🎜> }} var anotherFactorial = factorial;factorial = null;alert(anotherFactorial(4));  //24
    在非嚴格模式,使用遞歸函數時,用argument.callee代替函數名稱更保險
    在嚴格模式下,使用argument.callee會出錯,可用函數表達式代替函數宣告:
複製程式碼 程式碼如下:
函數表達式取代函數宣告
var factorial = function f(num){

    if (num         return 1;
  >    }
}



4、閉包


  指有權存取另一個函數作用域中的變數的函數。 (常見形式為函數巢狀)


複製程式碼 程式碼如下:function wai(pro ){
    return function(obj1,obj2){
        var val1 = obj1[pro];
               return - 1;
        }else if(val1>val2){
            return 1;        };
    }
}


    return匿名函數時,匿名函數的作用域鏈初始化為包含函數的活動物件和全域變數物件。即匿名函數包含wai()函數的作用域。
  每個函數被呼叫時,會建立一個執行環境、一個變數物件 和 對應的作用域鏈。


4-1.執行環境 及 作用域


  執行環境execution context簡稱環境,定義了變數和函數有權存取的其他數據,並決定他們的各自行為。   ①每個執行環境都有一個變數物件variable object,保存環境定義的所有變數和函數。該物件無法編碼訪問,但解析器在處理資料時會在後台使用它。

    全域變數物件是最外圍的一個執行環境。在網頁瀏覽器中被認為是window對象,故所有全域物件和函數都是window對象的屬性和方法所創建的。     執行環境中的程式碼執行完後,該環境就被銷毀,保存其中的變數和函數定義也隨之銷毀。

  ②程式碼在環境中執行時,會建立變數物件的一個作用域鏈scope chain,用於確保對執行環境有權存取的所有變數和函數的有序存取。

    作用域鏈前端,始終是目前執行的程式碼所在環境的變數物件。當該環境為函數時,會將活動物件作為變數物件。
    活動物件最開始只包含一個變量,即argumnt物件。
    作用域鏈中的下一個變數物件來自包含環境,而下一個變數物件來自下一個包含環境,直到延續到全域執行環境。

  ③標識符解析:從前段開始,沿著作用域鏈一級一級地搜尋標識符的過程。 【找不到通常會導致錯誤發生】



4-2.函數建立、執行時:

複製程式碼

        return 0;
    };
}
var result = compare(5 , 10🎜>}
var result = compare(5 , 10);
  ①建立函數compare()時,會建立一個預先包含全域變數物件的作用域鏈,並保存在內部[[scope]]屬性中。
  ②局部函數compare()的變數對象,只在函數執行的過程中存在。
   當調函數時,會建立一個執行環境,再透過複製函數的[[scope]]屬性中的物件 建構起執行環境的作用域鏈。
  ③第一次呼叫函數時,如compare(),會建立一個包含this、argument、val1 和 val2的活動物件。
  ④全域執行環境的變數物件(包括this、result、compare)在compare()執行環境的作用域鏈中處於第二位。
  ⑤作用域鏈 本質是一個指向變數物件的指標列表,只引用但不實際包含變數物件。
  ⑥無論何時在函數中存取一個變量,都會在行作用域鏈中搜尋具有對應名字的變數。

4-3.閉包的作用域鏈

  在另一個函數內部定義的函數會將包含函數的活動物件加入它的作用域鏈中。
  ①將函數物件賦值null,等於通知垃圾回收程式將其清除,隨著函數作用域鏈被銷毀,其作用域鏈(不除了全域作用域)也會被安全銷毀。
  ②由於閉包會攜帶包含函數的作用域,所以會比其他函數佔用更多記憶體。

4-4.閉包與變數

  作用域鏈的一個副作用:閉包只能取得包含函數中任何變數的最後一個值。

複製程式碼 程式碼如下:

function createFunctions(>

function createFunctions(>

function createFunctions()()( Array();
    for (var i=0; i         result[i] = function(){    }
    return result;
}

  ①createFunctions()函數,10個閉包賦值給陣列result,再回傳result陣列。每個閉包都會傳回自己的索引,但實際上都會回傳10。
   因為每個函數(閉包)的作用域鏈中都保存著createFunctions()函數的活動對象,所以它們引用的是同一個變數i,當createFunctions函數執行完後i的值10,故閉包中的i也都為10。
  ②解決辦法,不使用閉包,創建一個匿名函數,將i值賦值給其參數:
複製代碼 程式碼如下:

function createFunctions(){
    var result = new Array();
    [i] = function(num){
            return function(){
           >        }(i);
    }
    return result;
}


  建立一個每次循環都會執行一次的匿名函數:將每次循環時包圍函數的i值作為參數,存入匿名函數中。因為函數參數是按值傳遞的,而非引用,所以每個匿名函數中的num值 都為每個循環時i值的副本。

4-5.this物件

  this物件是在運行時基於函數的執行環境綁定的。     在全域函數中,this等於window;當函數被某物件呼叫時,this為該物件。

    匿名函數的執行環境具有全局性,其this物件通常指window。透過call()或spply()改變函數執行環境時,this指向其物件。

  ①每個函數在被呼叫時,都會自動取得兩個特殊變數:this和argument。內部函數在搜尋這兩個變數時,只會搜尋到期活動物件為止,永遠不可能存取外部函數的這兩個變數。
    不過將外部作用域的this物件保存在一個閉包能存取的變數裡,就可讓閉包存取該物件。



陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn