麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > JavaScript > 正文

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

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

函數(shù)表達式

1、JavaScript中定義函數(shù)有2鐘方法:

  1-1.函數(shù)聲明:

復制代碼 代碼如下:

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

    ①name屬性:可讀取函數(shù)名。非標準,瀏覽器支持:FF、Chrome、safari、Opera。
    ②函數(shù)聲明提升:指執(zhí)行代碼之前會先讀取函數(shù)聲明。即函數(shù)調用可置于函數(shù)聲明之前。

  1-2.函數(shù)表達式:

復制代碼 代碼如下:

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

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

if判斷中的重復函數(shù)聲明

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


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

if判斷 函數(shù)表達式

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


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

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

     ①若使用下列代碼調用該函數(shù),會出錯:
復制代碼 代碼如下:

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

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

解決方案

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

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


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

函數(shù)表達式代替函數(shù)聲明

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


4、閉包

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

復制代碼 代碼如下:

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匿名函數(shù)時,匿名函數(shù)的作用域鏈初始化為包含函數(shù)的活動對象和全局變量對象。即匿名函數(shù)包含wai()函數(shù)的作用域。
  每個函數(shù)被調用時,會創(chuàng)建一個執(zhí)行環(huán)境、一個變量對象 及 相應的作用域鏈。

4-1.執(zhí)行環(huán)境 及 作用域

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

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

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

4-2.函數(shù)創(chuàng)建、執(zhí)行時:

復制代碼 代碼如下:

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

  ①創(chuàng)建函數(shù)compare()時,會創(chuàng)建一個預先包含全局變量對象的作用域鏈,并保存在內部[[scope]]屬性中。
  ②局部函數(shù)compare()的變量對象,只在函數(shù)執(zhí)行的過程中存在。
   當調函數(shù)時,會創(chuàng)建一個執(zhí)行環(huán)境,再通過復制函數(shù)的[[scope]]屬性中的對象 構建起執(zhí)行環(huán)境的作用域鏈。
  ③第一次調用函數(shù)時,如compare(),會創(chuàng)建一個包含this、argument、val1 和 val2的活動對象。
  ④全局執(zhí)行環(huán)境的變量對象(包括this、result、compare)在compare()執(zhí)行環(huán)境的作用域鏈中處于第二位。
  ⑤作用域鏈 本質是一個指向變量對象的指針列表,只引用但不實際包含變量對象。
  ⑥無論什么時候在函數(shù)中訪問一個變量,都會行作用域鏈中搜索具有相應名字的變量。

4-3.閉包的作用域鏈

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

4-4.閉包與變量

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

復制代碼 代碼如下:

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

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

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

  創(chuàng)建一個每次循環(huán)都會執(zhí)行一次的匿名函數(shù):將每次循環(huán)時包圍函數(shù)的i值作為參數(shù),存入匿名函數(shù)中。因為函數(shù)參數(shù)是按值傳遞的,而非引用,所以每個匿名函數(shù)中的num值 都為每此循環(huán)時i值的一個副本。

4-5.this對象

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

復制代碼 代碼如下:

閉包 訪問外部函數(shù)的this對象

var name = "The Window";

var object = {
    name : "My Object",

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

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


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

5、函數(shù)聲明 轉換為 函數(shù)表達式

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

復制代碼 代碼如下:

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

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 国产成人高潮免费观看精品 | 久久精品影视 | 欧美一极视频 | 成人一级免费视频 | 久久综合给合久久狠狠狠97色69 | 免费毛片在线视频 | 精品亚洲网站 | 日韩黄色片网站 | 99riav视频一区二区 | 久久这| 国产午夜精品久久久久 | 男女一边摸一边做羞羞视频免费 | 亚洲日本韩国在线观看 | 日本中文字幕高清 | 欧美18—19sex性hd按摩 | 亚洲 综合 欧美 动漫 丝袜图 | 精品国产一区二区在线 | 国产午夜网 | 亚洲成人中文字幕在线 | 日韩一级网站 | 麻豆传传媒久久久爱 | 成人午夜视频免费 | 91精品国产91久久久久久 | 91av在线国产| 国产99视频精品免视看9 | 亚洲综合91| 玩偶姐姐在线观看免费 | 日本羞羞的午夜电视剧 | 国产毛片在线高清视频 | 日韩精品久久久久久久电影99爱 | 国产69精品久久久久9999不卡免费 | 高清一区二区在线观看 | 久久狠狠高潮亚洲精品 | 久久亚洲精品久久国产一区二区 | 欧美日韩一 | 成人黄色小视频网站 | 成人午夜影院 | 视频一区二区久久 | 曰批全过程120分钟免费69 | 国产精品视频成人 | 黄网站在线播放视频免费观看 |