亚洲免费人人妻人人,cao78在线视频,福建一级毛片,91精品视频免费观看,高清另类图片操逼,日本特黄特色大片免费看,超碰欧美人人澡曰曰澡夜夜泛

淺談js之閉包 -電腦資料

電腦資料 時間:2019-01-01 我要投稿
【m.msguai.com - 電腦資料】

    "官方"的解釋是指一個擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個函數(shù)),因而這些變量也是該表達(dá)式的一部分;

    紅皮書是這樣說的,閉包是指有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù);常見的創(chuàng)建閉包的方式就是在一個函數(shù)中再創(chuàng)建一個函數(shù);

    閉包是一種特殊的對象,

淺談js之閉包

。它由兩部分構(gòu)成:函數(shù),以及創(chuàng)建該函數(shù)的環(huán)境。環(huán)境由閉包創(chuàng)建時在作用域中的任何局部變量組成;

    光看定義是云里霧里,但是到了真正的代碼了又是什么樣的形式呢?經(jīng)典的閉包例子:

    function fn() {

    var name = 4;

    return function () {

    var n = 0;

    alert(++n);

    alert(++name);

    }

    }

    var fun = fn();

    fun();//n =>1,name=>5;

    fun();// n =>1,name=>6;

    這里就有閉包產(chǎn)生了,fun就是閉包;這個閉包由fn中的匿名函數(shù)和name變量構(gòu)成。,但是呢,它又是一種特殊的函數(shù),它是一種能能夠讀取其他函數(shù)內(nèi)部變量的特殊函數(shù);fn中的匿名函數(shù)的父函數(shù)在執(zhí)行完了之后,按正常來說,它應(yīng)該被銷毀,里面的變量也被銷毀,,但是里面的變量現(xiàn)在沒有被銷毀,而是被這個匿名函數(shù)引用著;(說實在的它不應(yīng)該被銷毀,因為這個匿名函數(shù)還沒有執(zhí)行,還要用上一級的函數(shù)的中的變量,你給我銷毀了,我可怎么辦,那不是讓我報錯呀,但是呢,我給你用,不銷毀,這又不符合規(guī)矩,按規(guī)矩是這樣的:當(dāng)一個函數(shù)執(zhí)行完之后,是要被立即銷毀的,執(zhí)行環(huán)境銷毀,里面的變量銷毀,你現(xiàn)在不讓我銷毀,那不亂套了,那怎么辦呢,于是乎,一群磚家,就說趕這種方式叫閉包吧)意思是說我跟你們不一樣;因為是特殊函數(shù),代碼的最后一句fun()執(zhí)行完之后,name變量還是沒有釋放,但是每次執(zhí)行fun,里面的n變量是都是新創(chuàng)建的,執(zhí)行完之后又釋放掉;要是你明白了就不需要看括號里的內(nèi)容了(這里我就形象的說為什么說name變量會一直在內(nèi)存中?在剛開始的時候,父函數(shù)fn在剛要執(zhí)行完了,開始銷毀時,匿名子函數(shù)就說了,我要用你的name變量,你先別銷毀了,父函數(shù)說好吧,于是乎,父函數(shù)執(zhí)行完之后(歸天了),就沒有銷毀name,在當(dāng)你調(diào)用fun,執(zhí)行匿名子函數(shù),fun()調(diào)用完了,你把自己家的n變量銷毀了,fun就說了name又不是我的東西,我就是用了一下,憑什么我給銷毀,我不給銷毀,但是這時父函數(shù)已經(jīng)去世了(執(zhí)行完了),于是就產(chǎn)生了內(nèi)存消耗,除非你手動銷毀,垃圾收回機制不會自動收回;這又牽扯到內(nèi)存泄漏,性能問題了,后面說。)

    作用域鏈:

    講到這里,如果要想整整的明白還有知道作用域鏈,和垃圾收回機制;

    我就說說上面代碼執(zhí)行時的作用域鏈:

    我就說說這張圖是什么意思,這種圖是執(zhí)行var fun = fu();fun();這兩句代碼時所發(fā)生的情況;

    其實匿名函數(shù)在fu()被返回時,它的作用域鏈就被初始化為包含全局變量對象和fu函數(shù)的活動對象;也就是說當(dāng)fu函數(shù)執(zhí)行完返回后,它的執(zhí)行環(huán)境會被銷毀,但是其活動對象不會被銷毀,仍然在內(nèi)存中,因為匿名函數(shù)的作用域鏈中引用了這個活動對象。只有到匿名函數(shù)被手動銷毀時才銷毀;其實在fu執(zhí)行完后,紅字顯示的部分就消失了,就活動變量沒有消失;

    再說一點關(guān)于作用域鏈的問題:

    1。作用域鏈中的變量對象(函數(shù)中叫活動對象)保存的是變量和函數(shù);

    2.作用域鏈的作用就是為了保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。

    3.查找一個變量是從作用域鏈的最前端,逐漸向上找,只要找到就不再向上找了,不論上面是否還有這個值;

    4.就以上面的fu函數(shù)為例吧,在聲明fu函數(shù)的時候就開始預(yù)先創(chuàng)建一個包含全局變量對象的作用域鏈了(如果嵌套多了,其實就是在函數(shù)聲明的地方創(chuàng)建父函數(shù)及其之上的作用域鏈),這個作用域鏈將被保存在剛創(chuàng)建函數(shù)的內(nèi)部[[Scope]]的屬性中;當(dāng)調(diào)用fu函數(shù)時,會為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境,然后通過復(fù)制函數(shù)的[[Scope]]中的作用域鏈構(gòu)建起執(zhí)行環(huán)境的作用域鏈;之后還要創(chuàng)建一個本函數(shù)的活動對象,并把這個活動對象推入執(zhí)行環(huán)境作用域鏈的前端。

    5.作用域鏈本質(zhì)上就是一個指向變量對象的指針列表。

    垃圾回收機制:

    再說說垃圾回收機制:

    1.如果一個對象不再有引用了,這個對象就會被GC收回;

    2,如果兩個對象互相引用,但不被第三個引用,這兩個互相引用的對象也會收回的。

    而閉包不再這個范疇之內(nèi)。

    閉包的特性:

    1.引用的變量不被垃圾回收機制收回

    2.函數(shù)內(nèi)部可以引用外部的變量;

    3.函數(shù)里面嵌套函數(shù)

    閉包的用處(好處):

    1.私有變量和方法

    var a=(function() {

    var privateNum = 1;

    function privateFun(val) {

    alert(val);

    }

    return {

    publicFun: function() {

    privateFun(2);

    },

    publicNum:function() {

    return privateNum;

    }

    }

    })();

    a.publicNum();//1

    a.publicFun();//2

    如果你用a.privateNum,a.privateFun();這是會報錯的。

    2.實現(xiàn)一些變量的累加

    function a() {

    var n=0;

    return function () {

    n++;

    alert(n);

    }

    }

    var b = a();

    b();//1

    b();//2

    b();//3

    這里只是要使用累加,就這樣干,具體還要具體分析,原理是這樣了

    因閉包產(chǎn)生的問題

    初學(xué)者常見的,循環(huán)閉包

    大部分我們所寫的 Web JavaScript. 代碼都是事件驅(qū)動的 — 定義某種行為,然后將其添加到用戶觸發(fā)的事件之上(比如點擊或者按鍵),

電腦資料

淺談js之閉包》(http://m.msguai.com)。我們的代碼通常添加為回調(diào):響應(yīng)事件而執(zhí)行的函數(shù)。

    閉包循環(huán)問題

    你不管點擊哪一個,都alert”我是5號“;

    原因就是你循環(huán)了五次產(chǎn)生了五個閉包,而這5個閉包共享一個變量i,說的明白一點就是,在for循環(huán)結(jié)束時,只是把這五個匿名函數(shù)注冊給click事件,當(dāng)時在循環(huán)的時候并沒有執(zhí)行,當(dāng)循環(huán)結(jié)束了,此時i的值是5;之后你去點擊p標(biāo)簽,你點擊哪一個就執(zhí)行哪一個對應(yīng)的匿名函數(shù)(這個時候才執(zhí)行),這時候匿名中發(fā)現(xiàn)一個i,匿名中沒有定義i,于是沿著作用域鏈找,找到了,但是這時候循環(huán)早就結(jié)束了,i等于5,于是彈出”我是5號“來;點擊其他的同理;

    怎么解決呢:

    一種方法是再創(chuàng)建一個閉包,把js代碼改為這樣就行了

    var page = document.getElementsByTagName("p");

    for(var i=0; i

    !function(num) {

    page[i].onclick = function () {

    alert("我是"+num+"號");

    }

    }(i)

    }

    我只說一點,這次五個閉包不共享num,而是創(chuàng)建五個num變量

    還有一種解決方式:

    var page = document.getElementsByTagName("p");

    for(var i=0; i

    page[i].num = i//先把每個變量值存起來

    page[i].onclick = function () {

    alert("我是"+this.num+"號");

    }

    }

    閉包中的this對象

    var num = 1;

    var bj = {

    num:2,

    getNum:function() {

    return function () {

    return this.num;

    }

    }

    }

    alert(obj.getNum()());//num -> 1

    為什么不彈出2呢,這里是說明閉包中你需要注意現(xiàn)在的this的指向那一個對象,其實記住一句話就永遠(yuǎn)不會用錯this的指向問題,this永遠(yuǎn)指向調(diào)用它的作用域;

    如果這樣寫你就可能理解了

    var num = 1;

    var bj = {

    num:2,

    getNum:function() {

    return function () {

    return this.num;

    }

    }

    }

    var a = obj.getNum();

    alert(window.a());//1

    其實是window對象調(diào)用的,這就是說閉包中的this讓你看不清this的指向;

    要是讓它alert 2你要這樣:

    var num = 1;

    var bj = {

    num:2,

    getNum:function() {

    var _this = this;//在這里保存this

    return function () {

    return _this.num;

    }

    }

    }

    var a = obj.getNum();

    alert(window.a());

    性能考量

    如果不是因為某些特殊任務(wù)而需要閉包,在沒有必要的情況下,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因為閉包對腳本性能具有負(fù)面影響,包括處理速度和內(nèi)存消耗。

    例如,在創(chuàng)建新的對象或者類時,方法通常應(yīng)該關(guān)聯(lián)于對象的原型,而不是定義到對象的構(gòu)造器中。原因是這將導(dǎo)致每次構(gòu)造器被調(diào)用,方法都會被重新賦值一次(也就是說,為每一個對象的創(chuàng)建)。

    function MyObject(name, message) {

    this.name = name.toString();

    this.message = message.toString();

    this.getName = function() {

    return this.name;

    };

    this.getMessage = function() {

    return this.message;

    };

    }

    應(yīng)該是這樣

    function MyObject(name, message) {

    this.name = name.toString();

    this.message = message.toString();

    }

    MyObject.prototype.getName = function() {

    return this.name;

    };

    MyObject.prototype.getMessage = function() {

    return this.message;

    };

    示例中,繼承的原型可以為所有對象共享,且不必在每一次創(chuàng)建對象時定義方法

最新文章