成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

javascript:閉包的總結

BigNerdCoding / 625人閱讀

摘要:當函數(shù)執(zhí)行完畢后,局部活動對象就會被銷毀,內存中僅保存全局作用域,但是閉包情況有所不同。閉包與變量副作用閉包只能取得外層函數(shù)中任何變量的最后一個值??梢栽L問變量,因為這個匿名函數(shù)時一個閉包,它能夠訪問包含作用域中的所有變量。

*前言:這次總結閉包,分別參考了《js高級程序設計》、廖雪峰老師的網站、還有《js忍著秘籍》,好了,廢話少說,黑喂狗~~~

---------------------嚴肅分割線-------------------*

1.js函數(shù)中的作用域鏈

沒錯,閉包還是要從作用域鏈說起,要理解閉包必須從函數(shù)第一次被調用時發(fā)生了什么入手,先看一個例子,代碼:

    function compare(value1,value2){
        if(value1 < value2){
            return -1;
        }else if(value1 > value2){
            return 1;
        }else{
            return 0;
        }
    }
    var result = compare(5,10);  //全局作用域中調用

首先定義了一個compare函數(shù),然后又在全局作用域中調用了它。當調用compare()時,會創(chuàng)建一個包含(this,arguments,value1,value2)的活動對象,而全局執(zhí)行環(huán)境的變量對象(this,result,compare)在compare()執(zhí)行環(huán)境的作用域鏈中處于第二位。在這例子中,當調用compare()函數(shù)時,會為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境,其作用域鏈包含兩個變量對象:本地活動對象和全局對象,在函數(shù)中訪問一個變量時,會先從本地作用域中查找,找不到則向上查找外層函數(shù)的作用域中是否有,直到全局作用域。當函數(shù)執(zhí)行完畢后,局部活動對象就會被銷毀,內存中僅保存全局作用域,但是閉包情況有所不同。

2.閉包中的作用域鏈

先看一個例子:

    function createComparisonFunction(propertyName){
        return function(object1,object2){
            var value1 = object1[propertyName];
            var value2 = object2[propertyName];
            
            if(value1 < value2){
                return -1;
            }else if(value1 > value2){
                return 1;
            }else{
                return 0;
            }
        };
    }

    var compareNames  = createComparisonFunction("name");
    var result = compareNames({name:"Jack"},{name:"Rose"});
    compareNames = null;   //銷毀匿名函數(shù)
    

上面的例子中,在createComparisonFunction函數(shù)內部定義了一個匿名函數(shù),它的作用域鏈包含外部函數(shù)createComparisonFunction()的活動對象和全局變量對象,所以匿名函數(shù)中可以訪問createComparisonFunction()函數(shù)中的propertyName。
最重要的是:createComparisonFunction()函數(shù)在執(zhí)行完畢后,它的執(zhí)行環(huán)境作用域鏈會被銷毀,其活動對象仍然會留在內存中,這就是為什么上面的代碼中,執(zhí)行:
var compare = createComparisonFunction("name")之后,createComparisonFunction()函數(shù)已經執(zhí)行完畢,但是仍然可以在下一行代碼中執(zhí)行比較大小的操作。
創(chuàng)建的比較函數(shù)被保存在變量compareNames中,設置它等于null,解除該函數(shù)引用,垃圾回收。

3.閉包與變量 副作用:

閉包只能取得外層函數(shù)中任何變量的最后一個值。看下面例子:

    function createFunctions(){
        var arr = new Array();
        for(var i=0; i<10;i++){
            arr[i] = function(){
                return i;
            };
        }
        return arr;
    }
    
    var result = createFunctions();
    var f1 = result[0];
    var f2 = result[1];
    var f3 = result[2];
    //執(zhí)行函數(shù)
    alert(f1());    //10
    alert(f2());    //10
    alert(f3());    //10

這個例子中似乎每個函數(shù)都應該返回自己的索引值,實際上每個匿名函數(shù)返回的都是10。因為每個匿名函數(shù)中都保存著createFunctions()函數(shù)的活動對象,所以它們引用的是同一個變量i,函數(shù)createFunctions()返回后,變量i的值都是10,此時每個函數(shù)都引用著保存變量i的同一個變量對象,所以每個函數(shù)內部i的值都是10.

注意:上述函數(shù)的調用過程:執(zhí)行createFunctions()函數(shù),并且把函數(shù)執(zhí)行結果賦值給變量result,現(xiàn)在result是一個數(shù)組,再把result[0]賦值給f1,f1實際上代表的是內部的匿名函數(shù),現(xiàn)在執(zhí)行這個函數(shù):f1(),就會得到i的值。

改造

可以通過創(chuàng)建另一個匿名函數(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;
    }
    
    var final = createFunctions();
    var f1 = final[0];
    alert(f1());   //0

這次沒有直接把閉包賦值給數(shù)組,而是定義了一個匿名函數(shù),并立即執(zhí)行該函數(shù)的結果賦值給數(shù)組。這個匿名函數(shù)有一個參數(shù)num,也就是最終要返回的值,調用這個匿名函數(shù)時,傳入了變量i,由于函數(shù)參數(shù)是按值傳遞的,所以會把變量i的當前值傳遞給num,這個匿名函數(shù)內部,又創(chuàng)建并返回了一個訪問num的閉包,這樣,最里面的匿名函數(shù)會鎖住外層匿名函數(shù)傳遞進來的num值即當前i的值,并且返回num,這樣num就會等于此時的i的值并且賦值給數(shù)組。

4.閉包就是匿名函數(shù)嗎?

上述代碼中很容易讓人誤解:閉包就是一個匿名函數(shù),其實不然,看下面例子:

    var outName = "外面的名字";
    var later;
    function outerFunction(){
        var innerName = "里面的名字";
        
        function innerFunction(){
            alert("I can see the "+outName);
            alert("I can see the "+innerName);
        }
        later = innerFunction;
    }
    outerFunction();
    later();

上述代碼中,在outerFunction()函數(shù)中,將內部函數(shù)innerFunction()賦值給全局變量later,執(zhí)行完倒數(shù)第二步:outerFunction();之后,執(zhí)行later();依然可以可以訪問到內部變量innerName。
因為在外部函數(shù)outerFunction中聲明innerFunction()函數(shù)時,不僅聲明了函數(shù),還創(chuàng)建了一個閉包,該閉包不僅包含函數(shù)聲明,還包含了函數(shù)聲明的那一時刻該作用域中的所有變量。

5.閉包的用處 私有變量

上述例子可以看出,閉包可以用來封裝私有變量,就像java中的在對象內部封裝一個private私有變量一樣。
看下面例子:

    function createCounter(){
        var num = 0;
        this.getNum = function(){
            return num;
        };
        this.num = function(){
            num++;
        };
    }
    
    var counter = new createCounter();
    counter.num()  //調用計數(shù)器一次,使num值加1
    //測試代碼
    alert(counter.getNum());  //1
    alert(counter.num());    //undefined
    

上面例子中用構造函數(shù)模式創(chuàng)建了一個計數(shù)器函數(shù),然后對函數(shù)進行實例化,在構造函數(shù)內部,我們定義了一個變量num,它的可訪問性只能在構造器內部,定義了一個getNum()方法,該方法只能對內部變量進行讀取,但不能寫入。然后又定義了方法num(),通過最后兩行測試代碼可以看出,可以通過存取方法getNum獲取私有變量,但是不能直接訪問私有變量。

總結:私有變量的意思是,我們如果想對num進行加減乘除的操作,只能在createCounter內部,外部只能訪問內部進行邏輯操作后的值,而不能訪問帶有對num值進行操作的方法,這樣,我們就可以把自己的業(yè)務邏輯封裝在函數(shù)內部的閉包中,只需要暴露出接口讓外部獲取想要得到的值就可以了,也就是說主動權完全在你定義函數(shù)時,外部只能看和獲取,而不能進行對變量值的改變的操作。

上述的目的就是創(chuàng)建一個用于訪問私有變量的公有方法??聪旅娲a:

    function Person(name){
        this.getName = function(){
            return name;
        };
        this.setName = function(){
            name = value;
        };
    }
    
    //測試
    var person = new Person("Jack");
    alert(person.getName());     //Jack
    person.setName("Rose");
    alert(person.getName());     //Rose

上面的代碼在構造函數(shù)內部定義了兩個方法:setName和getName,這兩個方法都可以在構造函數(shù)外部訪問和實用,而且都有權訪問私有變量name,但在Person構造函數(shù)外部,沒有任何辦法訪問name,由于這兩個方法是在構造函數(shù)內部定義的,所以做為閉包能夠通過作用域鏈訪問name。上述在構造函數(shù)中定義特權方法有一個缺點,就是必須要使用構造函數(shù)模式來達到這個目的,這樣針對每個實例都會創(chuàng)建同樣一組新方法。

解決辦法:靜態(tài)私有變量
看下面代碼:

    (function(){
        var name = "";
        Person = function(value){
            name = value;
        };
        Person.prototype.getName = function(){
            return name;
        };
        Person.prototype.setName = function(value){
            name = value;
        };
    })();
    
    //測試函數(shù)
    var person1 = new Person("Jack");
    alert(person1.getName());         //Jack
    person1.setName("Rose");
    alert(person1.getName());         //Rose
    
    var person2 = new Person("Will");
    alert(person1.getName());          //Will
    alert(person2.getName());          //Will
   

上述代碼中,Person構造函數(shù)與getName()和setName()方法一樣,都有權訪問私有變量name,name變成了一個靜態(tài)的、由所有實例共享的屬性。在一個實例上調用setName會影響所有的實例。或者新建一個Person實例都會賦予name屬性一個新值。

上述兩個方法:第二種創(chuàng)建靜態(tài)私有變量會因為使用原型而增進代碼復用,但每個實例都沒有自己的私有變量。

模仿塊級作用域

上面舉過例子,js沒有塊級作用域,可以通過匿名函數(shù)立即執(zhí)行把塊級作用域包裹起來,這樣就有了塊級作用域??聪旅娲a:

    function outputNumbers(count){
        (function(){
            for(var i = 0; i

上述函數(shù)中,在for循環(huán)外部插入了一個私有作用域,在匿名函數(shù)中定義的任何變量,都會在匿名函數(shù)執(zhí)行結束時被銷毀。因此變量i只能在for循環(huán)中使用,使用后即被銷毀,因此上面的代碼執(zhí)行會這樣:
1.執(zhí)行測試函數(shù)后,會彈出5個彈窗,會顯示0,1,2,3,4
2.執(zhí)行完匿名函數(shù)后,i即被銷毀,所以執(zhí)行alert(i);會報錯。
3.可以訪問變量count,因為這個匿名函數(shù)時一個閉包,它能夠訪問包含作用域中的所有變量。

這種技術經常在全局作用域中被用在函數(shù)外部,從而限制向全局作用域中添加過多的變量和函數(shù),看下面代碼:

    (function(){
        var now = new Date();
        if(now.getMonth() == 0 && now.getDate() == 1){
            alert("元旦快樂");
        }
    })();

上述代碼放在全局作用域中,可以用來確定哪一天時1月1日元旦,now是匿名函數(shù)中的局部變量,不用在全局作用域中創(chuàng)建它。

先寫這么多吧,以后再添加~~~~~

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://m.hztianpu.com/yun/79707.html

相關文章

  • 還擔心面試官問閉包?

    摘要:一言以蔽之,閉包,你就得掌握。當函數(shù)記住并訪問所在的詞法作用域,閉包就產生了。所以閉包才會得以實現(xiàn)。從技術上講,這就是閉包。執(zhí)行后,他的內部作用域并不會消失,函數(shù)依然保持有作用域的閉包。 網上總結閉包的文章已經爛大街了,不敢說筆者這篇文章多么多么xxx,只是個人理解總結。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結與《JavaScript忍者秘籍》 《你不知道的JavaScri...

    tinyq 評論0 收藏0
  • JavaScript閉包

    摘要:閉包引起的內存泄漏總結從理論的角度將由于作用域鏈的特性中所有函數(shù)都是閉包但是從應用的角度來說只有當函數(shù)以返回值返回或者當函數(shù)以參數(shù)形式使用或者當函數(shù)中自由變量在函數(shù)外被引用時才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經典書籍等書中給出的概念,這些概念雖然...

    HmyBmny 評論0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內優(yōu)雅的實現(xiàn)文件分片斷點續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應用添加全局功能的一種強大而且簡單的方式。插....

    izhuhaodev 評論0 收藏0
  • 通過示例學習JavaScript閉包

    摘要:譯者按在上一篇博客,我們通過實現(xiàn)一個計數(shù)器,了解了如何使用閉包,這篇博客將提供一些代碼示例,幫助大家理解閉包。然而,如果通過代碼示例去理解閉包,則簡單很多。不過,將閉包簡單地看做局部變量,理解起來會更加簡單。 - 譯者按: 在上一篇博客,我們通過實現(xiàn)一個計數(shù)器,了解了如何使用閉包(Closure),這篇博客將提供一些代碼示例,幫助大家理解閉包。 原文: JavaScript Clos...

    xingpingz 評論0 收藏0
  • Js學習筆記:閉包

    摘要:一前言這個周末,注意力都在學習基礎知識上面,剛好看到了閉包這個神圣的東西,所以打算把這兩天學到的總結下來,算是鞏固自己所學。因此要注意閉包的使用,否則會導致性能問題。五總結閉包的作用能夠讀取其他函數(shù)內部變量。 # 一、前言 這個周末,注意力都在學習基礎Js知識上面,剛好看到了閉包這個神圣的東西,所以打算把這兩天學到的總結下來,算是鞏固自己所學。也可能有些不正確的地方,也請大家看到了,麻...

    Crazy_Coder 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<