亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入Javascript函數、遞歸與閉包(執行環境、變量對象與作用域鏈)使用詳解

2019-11-20 22:43:56
字體:
來源:轉載
供稿:網友

函數表達式

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

  1-1.函數聲明:

復制代碼 代碼如下:

function funcName(arg1,arg2,arg3){
  //函數體
}

   ?、賜ame屬性:可讀取函數名。非標準,瀏覽器支持:FF、Chrome、safari、Opera。
   ?、诤瘮德暶魈嵘褐笀绦写a之前會先讀取函數聲明。即函數調用可置于函數聲明之前。

  1-2.函數表達式:

復制代碼 代碼如下:

var funcName = function(arg1,arg2,arg3){
  //函數體
};

    ①匿名函數(anonymous function,或拉姆達函數):function關鍵字后無標識符,name屬性值為空字符串。在把函數當成值使用時,都可用匿名函數。
    ②類似其他表達式,函數表達式使用前需先賦值,故不存在"函數聲明提升"那樣的作用。
    ③ECMAScript中的無效函數語法:
復制代碼 代碼如下:

if判斷中的重復函數聲明

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


      瀏覽器JavaScript引擎修正錯誤差異:大多瀏覽器會返回第二個聲明,忽略condition;FF則會在condition為true時返回第一個聲明。
      使用函數表達式可解決并實現:
復制代碼 代碼如下:

if判斷 函數表達式

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


2、遞歸
  遞歸函數,是在一個函數中通過名字調用自身的情況下構成的。
復制代碼 代碼如下:

function factorial(num){   //一個經典的遞歸階乘函數
    if (num <= 1){
        return 1;
    } else {
        return num * factorial(num-1);
    }
}

    ?、偃羰褂孟铝写a調用該函數,會出錯:
復制代碼 代碼如下:

var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4));

      將factorial()函數保存到變量anotherFactorial中后,將factorial變量設為null后不再引用函數,而anotherFactorial(4)中要執行factorial()函數,故出錯。
      使用argument.callee(指向正在執行的函數的指針)可解決:
復制代碼 代碼如下:

解決方案

function factorial(num){
    if (num <= 1){
        return 1;
    } else {
        return num * arguments.callee(num-1);
    }
}

var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4));  //24


    在非嚴格模式,使用遞歸函數時,用argument.callee代替函數名更保險
    在嚴格模式下,使用argument.callee會出錯,可用函數表達式 代替 函數聲明:
復制代碼 代碼如下:

函數表達式代替函數聲明

var factorial = function f(num){
    if (num <= 1){
        return 1;
    } else {
        return num * f(num-1);
    }
}


4、閉包

  指有權訪問另一個函數作用域中的變量的函數。(常見形式為函數嵌套)

復制代碼 代碼如下:

function wai(pro){
    return function(obj1,obj2){
        var val1 = obj1[pro];
        var val2 = obj2[pro];
        if(val1<val2){
            return -1;
        }else if(val1>val2){
            return 1;
        }else{
            return 0;
        };
    }
}

    return匿名函數時,匿名函數的作用域鏈初始化為包含函數的活動對象和全局變量對象。即匿名函數包含wai()函數的作用域。
  每個函數被調用時,會創建一個執行環境、一個變量對象 及 相應的作用域鏈。

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

  執行環境execution context簡稱環境,定義了變量和函數有權訪問的其他數據,并決定他們的各自行為。
 ?、倜總€執行環境都有一個變量對象variable object,保存環境定義的所有變量和函數。該對象無法編碼訪問,但解析器在處理數據時會在后臺使用它。
    全局變量對象是最外圍的一個執行環境。在Web瀏覽器中被認為是window對象,故所有全局對象和函數都是window對象的屬性和方法創建的。
    執行環境中的代碼執行完后,該環境就被銷毀,保存其中的變量和函數定義也隨之銷毀。

  ②代碼在環境中執行時,會創建變量對象的一個作用域鏈scope chain,用于保證對執行環境有權訪問的所有變量和函數的有序訪問。
    作用域鏈前端,始終是當前執行的代碼所在環境的變量對象。當該環境為函數時,會將活動對象作為變量對象。
    活動對象最開始只包含一個變量,即argumnt對象。
    作用域鏈中的下一個變量對象來自包含環境,而下一個變量對象來自下一個包含環境,直至延續到全局執行環境。

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

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

復制代碼 代碼如下:

function compare(val1,val2){
     if(val1<val2){
        return -1;
    }else if(val1>val2){
        return 1;
    }else{
        return 0;
    };
}
var result = compare(5 , 10);

  ①創建函數compare()時,會創建一個預先包含全局變量對象的作用域鏈,并保存在內部[[scope]]屬性中。
 ?、诰植亢瘮礳ompare()的變量對象,只在函數執行的過程中存在。
   當調函數時,會創建一個執行環境,再通過復制函數的[[scope]]屬性中的對象 構建起執行環境的作用域鏈。
 ?、鄣谝淮握{用函數時,如compare(),會創建一個包含this、argument、val1 和 val2的活動對象。
  ④全局執行環境的變量對象(包括this、result、compare)在compare()執行環境的作用域鏈中處于第二位。
 ?、葑饔糜蜴?本質是一個指向變量對象的指針列表,只引用但不實際包含變量對象。
 ?、逕o論什么時候在函數中訪問一個變量,都會行作用域鏈中搜索具有相應名字的變量。

4-3.閉包的作用域鏈

  在另外一個函數內部定義的函數會將包含函數的活動對象添加到它的作用域鏈中。
  ①將函數對象賦值null,等于通知垃圾回收例程將其清除,隨著函數作用域鏈被銷毀,其作用域鏈(不除了全局作用域)也會被安全銷毀。
  ②由于閉包會攜帶包含函數的作用域,所以會比其他函數占用更多內存。

4-4.閉包與變量

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

復制代碼 代碼如下:

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

 ?、賑reateFunctions()函數,將10個閉包賦值給數組result,再返回result數組。每個閉包都返回自己的索引,但實際上都返回10。
   因為每個函數(閉包)的作用域鏈中都保存著createFunctions()函數的活動對象,所以它們引用的是同一個變量i,當createFunctions函數執行完后i的值10,故閉包中的i也都為10。
 ?、诮鉀Q辦法,不使用閉包,創建一個匿名函數,將i值賦值給其參數:
復制代碼 代碼如下:

function createFunctions(){
    var result = new Array();
    for (var i=0; i < 10; i++){
        result[i] = function(num){
            return function(){
                return num;
            };
        }(i);
    }
    return result;
}

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

4-5.this對象

  this對象是在運行時基于函數的執行環境綁定的。
    在全局函數中,this等于window;當函數被某對象調用時,this為該對象。
    匿名函數的執行環境有全局性,其this對象通常指window。通過call()或spply()改變函數執行環境時,this指向其對象。
 ?、倜總€函數在被調用時,都會自動取得兩個特殊變量:this和argument。內部函數在搜索這兩個變量時,只會搜索到期活動對象為止,永遠不可能訪問外部函數的這兩個變量。
    不過將外部作用域的this對象保存在一個閉包能訪問的變量里,就可讓閉包訪問該對象。

復制代碼 代碼如下:

閉包 訪問外部函數的this對象

var name = "The Window";

var object = {
    name : "My Object",

    getNameFunc : function(){
        var that = this;
        return function(){
            return that.name;
        };
    }
};

alert(object.getNameFunc()());  //"MyObject"


   包圍函數的argument對象 也可通過此方法被閉包訪問。

5、函數聲明 轉換為 函數表達式

  JavaScript將function關鍵字昨晚函數聲明的開始,但函數聲明后面不能跟圓括號,所以function(){......}();會出錯。
  要將函數聲明轉換為函數表達式,需為函數聲明加一對圓括號:

復制代碼 代碼如下:

(function(){
   //塊級作用域
})();

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
韩国视频理论视频久久| 久久精品免费电影| 日韩在线观看av| 欧美激情视频网| 原创国产精品91| 亚洲电影免费观看高清完整版在线观看| 久久久久国产视频| 亚洲成人中文字幕| 欧美性猛交xxxx富婆弯腰| 亚洲欧美国产制服动漫| 精品爽片免费看久久| 久久视频在线直播| 国产成人jvid在线播放| 久久天天躁狠狠躁老女人| 97视频在线观看免费高清完整版在线观看| 成人乱人伦精品视频在线观看| 一区二区成人精品| 国内精品久久久久久中文字幕| 欧美精品在线免费观看| 亚洲片在线资源| 久久久成人的性感天堂| 亚洲欧洲激情在线| 日韩亚洲成人av在线| 57pao国产成人免费| 欧美激情三级免费| 亚洲精品小视频| 日韩在线视频网站| 国产精品美女999| 午夜精品久久久久久99热| 久久综合久久美利坚合众国| 亚洲女人天堂av| 国产精品久久久久久久久借妻| 久久久亚洲国产天美传媒修理工| 国产成人精品日本亚洲专区61| 欧美伦理91i| 91夜夜揉人人捏人人添红杏| 亚洲精品久久久久国产| 亚洲精品国产综合区久久久久久久| 久久久亚洲国产天美传媒修理工| 国内精品久久久久久中文字幕| 精品国产欧美一区二区五十路| 国产精品永久免费| 清纯唯美亚洲综合| 欧美精品999| www.xxxx精品| 亚洲精品美女久久| 在线观看视频99| 国产精品久久久av| 亚洲精品国产美女| 一区三区二区视频| 国产日韩精品电影| 国产69精品久久久久9| 亚洲国产精品久久久久秋霞不卡| 欧美另类69精品久久久久9999| 欧美国产极速在线| 欧美久久精品午夜青青大伊人| 91精品国产免费久久久久久| 成人黄色免费在线观看| 欧美日韩在线视频一区| 日韩中文字幕在线精品| 日韩欧亚中文在线| 性色av一区二区咪爱| 日韩亚洲精品电影| 自拍视频国产精品| 国产亚洲欧美日韩精品| 国产精品天天狠天天看| 亚洲午夜小视频| 亚洲欧洲在线播放| 欧美理论电影网| 97香蕉超级碰碰久久免费软件| 国产精品日韩在线| 在线观看日韩欧美| 日韩精品免费在线观看| 欧美日韩中文字幕在线视频| 亚洲精品国产拍免费91在线| 国产精品91在线观看| 日韩成人在线播放| 国产一区二区黑人欧美xxxx| 日韩在线视频导航| 夜色77av精品影院| 久久av资源网站| 69视频在线播放| 欧美成人免费va影院高清| 亚洲a成v人在线观看| 精品国产一区二区三区久久久狼| 亚洲一区二区三区成人在线视频精品| 日韩美女在线播放| 国产亚洲精品美女久久久久| 日韩美女视频免费在线观看| 欧美精品在线免费| 亚洲aⅴ男人的天堂在线观看| 成人激情电影一区二区| 色偷偷亚洲男人天堂| 欧美性黄网官网| 欧美福利视频在线观看| 91欧美激情另类亚洲| 不卡av在线网站| 色天天综合狠狠色| 国产伦精品一区二区三区精品视频| 日本精品一区二区三区在线播放视频| 国产日韩欧美自拍| 日本高清视频一区| 九九热这里只有精品免费看| 国产有码在线一区二区视频| 日本精品免费观看| 国产国语videosex另类| 久久久久久亚洲精品不卡| 日韩在线高清视频| 久久99热精品| 中文字幕综合一区| 亚洲精品国产精品国自产观看浪潮| 国产亚洲欧洲高清一区| 97欧美精品一区二区三区| 美女啪啪无遮挡免费久久网站| 日韩小视频在线| 日韩免费在线视频| 欧美激情视频播放| 日本午夜人人精品| 色偷偷91综合久久噜噜| 亚洲欧美激情四射在线日| 亚洲午夜精品视频| 91精品国产色综合| 成人xvideos免费视频| 国产一区二区三区丝袜| 成人黄色av网站| 欧美精品999| 中文字幕精品久久久久| 国产亚洲视频在线| 久久久国产精品一区| 国产精品视频男人的天堂| 国产精品直播网红| 亚洲无亚洲人成网站77777| 欧美电影免费观看高清| 亚洲第一av网| 国产精品91在线| 亚洲精品国产精品国自产观看浪潮| 国产日韩欧美夫妻视频在线观看| 久久网福利资源网站| 一本色道久久综合狠狠躁篇怎么玩| 国产成人黄色av| 日韩成人xxxx| 欧美一级淫片丝袜脚交| 视频直播国产精品| 91精品国产自产在线老师啪| 久久av红桃一区二区小说| 亚洲国产99精品国自产| 91精品国产成人| 国产精品美女久久久久av超清| 欧美激情中文网| 亚洲高清一二三区| 亚洲国产精彩中文乱码av在线播放| 欧美日韩国产在线| 亚洲激情视频在线播放| 性色av一区二区三区红粉影视| 欧美性生交大片免费| 国产精品久久久久999| 97视频在线看| 91干在线观看| 亚洲成人a**站| 一区二区三区 在线观看视| 国产一区二区三区免费视频| 91精品成人久久| 欧美日韩国产影院| 秋霞av国产精品一区|