国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識百科 - 正文

JavaScript閉包原理與用法實(shí)例分析

來源:懂視網(wǎng) 責(zé)編:小采 時間:2020-11-27 22:10:21
文檔

JavaScript閉包原理與用法實(shí)例分析

JavaScript閉包原理與用法實(shí)例分析:本文實(shí)例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下: 1、與閉包有關(guān)的兩個概念: 1) 變量的作用域 不帶有關(guān)鍵字var的變量會成為全局變量; 在函數(shù)中使用關(guān)鍵字var聲明的變量是局部變量。 局部變量只有在函數(shù)內(nèi)部才能訪問到,在函數(shù)外
推薦度:
導(dǎo)讀JavaScript閉包原理與用法實(shí)例分析:本文實(shí)例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下: 1、與閉包有關(guān)的兩個概念: 1) 變量的作用域 不帶有關(guān)鍵字var的變量會成為全局變量; 在函數(shù)中使用關(guān)鍵字var聲明的變量是局部變量。 局部變量只有在函數(shù)內(nèi)部才能訪問到,在函數(shù)外

本文實(shí)例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下:

1、與閉包有關(guān)的兩個概念:

1) 變量的作用域

不帶有關(guān)鍵字var的變量會成為全局變量;

在函數(shù)中使用關(guān)鍵字var聲明的變量是局部變量。

局部變量只有在函數(shù)內(nèi)部才能訪問到,在函數(shù)外面是訪問不到的。但在函數(shù)內(nèi)部可以通過作用域鏈一直向上搜索直到全局對象,也就是說,函數(shù)內(nèi)部可以訪問函數(shù)外部的變量。

2) 變量的生存周期

對于全局變量,其生存周期是永久的,除非主動銷毀這個全局變量;

而對于在函數(shù)內(nèi)用關(guān)鍵字var聲明的局部變量,當(dāng)退出函數(shù)時,這些局部變量會隨著函數(shù)調(diào)用結(jié)束而被銷毀。

var func = function() {
 var i = 1;
 alert(i); // 
輸出:1 }; alert(i); // 報錯:i is not defind.

例外情況:閉包

var func = function() {
 var i = 1;
 return function() {
 alert(i);
 i++;
 }
};
var f1 = func();
f1(); // 
輸出:1 f1(); // 輸出:2 var f2 = func(); f2(); // 輸出:1 f2(); // 輸出:2

2、從閉包的一個經(jīng)典應(yīng)用談起

<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<script>
 var divs = document.getElementsByTagName("div");
 for (var i = 0; i < divs.length; i++) {
 divs[i].onclick = function() {
 alert(i);
 };
 }
</script>

問題:無論單擊哪個div,都會彈出5。

原因:onclick事件是異步觸發(fā)的,當(dāng)事件被觸發(fā)時,for循環(huán)早已結(jié)束,此時變量i的值早已經(jīng)是5。

解決:在閉包的幫助下,把每次循環(huán)的i值都封閉起來。當(dāng)事件函數(shù)順著作用域鏈從內(nèi)到外查找變量i時,會先找到被封閉在閉包環(huán)境的i,單擊div時,會分別輸出0,1,2,3,4。

<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<script>
var divs = document.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
 divs[i].onclick = (function(num) {
 return function() {
 alert(num);
 };
 })(i);
}
</script>

類似實(shí)例:閉包直接賦給數(shù)組

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

結(jié)果:result的每個元素都返回10。

說明:閉包的作用域鏈有明顯的副作用——閉包總是獲得外部函數(shù)變量的最終值。上面代碼中,外部函數(shù)產(chǎn)生一個函數(shù)數(shù)組result并返回。函數(shù)數(shù)組中的每個元素都是一個函數(shù),每個函數(shù)都返回 i變量。似乎每個函數(shù)應(yīng)該返回每次循環(huán)的i值,即依次返回0到9,但事實(shí)是,每個函數(shù)的返回結(jié)果都是10。這是因為每個內(nèi)部函數(shù)返回的是變量i,而不是i在某個時刻的特定值,而i的作用域是整個外部函數(shù),當(dāng)外部函數(shù)執(zhí)行完成后,i的值是10。

解決:在每個內(nèi)部函數(shù)的內(nèi)部,再產(chǎn)生一個匿名函數(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;
}
for (var i = 0; i < 10; i++)
 alert(createFunctions()[i]());

結(jié)果:result依次返回0到9。

說明:(i)使得該層匿名函數(shù)立即執(zhí)行。

3、閉包

有時候需要得到函數(shù)內(nèi)的局部變量。如何從外部讀取局部變量?那就是在函數(shù)的內(nèi)部,再定義一個函數(shù)。

閉包是指有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù),創(chuàng)建閉包的最常見的方式就是在一個函數(shù)內(nèi)創(chuàng)建另一個函數(shù),通過另一個函數(shù)訪問這個函數(shù)的局部變量,利用閉包可以突破作用鏈域,將函數(shù)內(nèi)部的變量和方法傳遞到外部。

① 閉包的原理

1) 后臺執(zhí)行環(huán)境中,閉包的作用域鏈包含著自己的作用域、函數(shù)的作用域和全局作用域。

2) 通常,函數(shù)的作用域和變量會在函數(shù)執(zhí)行結(jié)束后銷毀。

3) 但是,當(dāng)函數(shù)返回一個閉包時,這個函數(shù)的作用域?qū)恢痹趦?nèi)存中保存到閉包不存在為止。

② 閉包的特性

1) 函數(shù)內(nèi)再嵌套函數(shù)。

2) 內(nèi)部函數(shù)可以引用外層的參數(shù)和變量。

3) 參數(shù)和變量不會被垃圾回收機(jī)制回收。

③ 閉包的用途

1) 讀取函數(shù)內(nèi)部的變量。

function f1(){
 var n = 999;
 function f2(){
 alert(n);//999
 }
}

在上面的代碼中,函數(shù)f2就被包括在函數(shù)f1內(nèi)部,這時f1內(nèi)部的所有局部變量,對f2都是可見的。但是反過來就不行,f2內(nèi)部的局部變量,對f1就是不可見的。既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,就可以在f1外部讀取它的內(nèi)部變量了。

function f1(){
 var n = 999;
 function f2(){
 alert(n);
 }
 return f2;
}
var result=f1();
result();//999

閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。由于在Javascript語言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,因此可以把閉包簡單理解成"定義在一個函數(shù)內(nèi)部的函數(shù)"。所以,在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來的一座橋梁。

function f1(){
 var n = 999;
 nAdd = function(){n += 1}
 function f2(){
 alert(n);
 }
 return f2;
}
var result=f1();
result();//999
nAdd();
result();//1000

result實(shí)際上就是閉包f2函數(shù)。它一共運(yùn)行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數(shù)f1中的局部變量n一直保存在內(nèi)存中,并沒有在f1調(diào)用后被自動清除。原因就在于f1是f2的父函數(shù),而f2被賦給了一個全局變量,這導(dǎo)致f2始終在內(nèi)存中,而f2的存在依賴于f1,因此f1也始終在內(nèi)存中,不會在調(diào)用結(jié)束后,被垃圾回收機(jī)制回收。

2) 讓函數(shù)內(nèi)部的變量的值始終保持在內(nèi)存中(延長局部變量的壽命)。

var print, add, set;
function closure() {
 var number = 8;
 print = function() {
 alert(number);
 }
 add = function() {
 number++;
 }
 set = function(x) {
 number = x;
 }
}
closure();//創(chuàng)建一個閉包
add();
print();//9
set(0);
print();//0
var oldClosure = print;
closure();//創(chuàng)建一個新的閉包
print();//8
oldClosure();//0

使用閉包的注意點(diǎn):由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。也就是說,閉包會引用外部函數(shù)作用域,會占用更多的內(nèi)存,過度使用閉包,會導(dǎo)致性能問題。所以,僅當(dāng)必要時才使用閉包。對產(chǎn)生閉包的函數(shù),使用后應(yīng)該解除引用。

3)自執(zhí)行函數(shù)+閉包減少全局變量污染(封裝私有變量)

var person = (function() {
 var_name = "Alice";
 var _id = 16;
 return {
 getUserInfo: function() {
 return _name + ": " + _id;
 }
 }
})();

使用下劃線來約定私有變量_name和_age,它們被封裝在閉包產(chǎn)生的作用域中,外部是訪問不到這兩個變量的,這就避免了對全局的命令污染。

④ 閉包的缺點(diǎn):

1) 需要維護(hù)額外的作用域。

2) 過渡使用閉包會占用大量內(nèi)存。

4、this對象

在閉包內(nèi)使用this對象將產(chǎn)生一些復(fù)雜的行為。this對象的值基于函數(shù)所在的執(zhí)行環(huán)境在運(yùn)行時決定:在全局函數(shù)中使用時,this等于window(非嚴(yán)格模式)或undefined(嚴(yán)格模式);而當(dāng)作為對象的方法調(diào)用時,this等于這個對象。

var name = "The window";
var object = {
 name: "My object",
 getName: function() {
 return function() {
 return this.name;
 };
 }
};
alert(object.getName()());//
輸出:"The window"

每個函數(shù)一旦被調(diào)用,它將自動獲得this和arguments兩個變量。一個內(nèi)部函數(shù)是不能直接從外部函數(shù)訪問到這兩個變量的??梢酝ㄟ^將this對象存儲在另一個變量中來解決這個問題。把外部作用域中的this對象保存在一個閉包能夠訪問到的變量里,就可以讓閉包訪問該對象了。

var name ="The window";
var object = {
 name: "My object",
 getName: function() {
 var that = this;
 return function() {
 return that.name;
 };
 }
};
alert(object.getName()());//
輸出:"My object"

要讓閉包訪問外部函數(shù)的this和arguments對象,可以通過將它們的引用存儲在另一個變量中來完成。

5、內(nèi)存泄漏

使用閉包的時候很容易造成循環(huán)引用,若閉包的作用域包含著一些DOM節(jié)點(diǎn),這時候就有可能造成內(nèi)存泄漏,但其實(shí),這本身不是閉包的問題,而是由于:BOM和DOM中的對象是使用C++以COM對象的方式實(shí)現(xiàn)的,而COM對象的垃圾收集機(jī)制采用的是引用計數(shù)策略,在基于引用計數(shù)策略的垃圾回收機(jī)制中,若兩個對象之間形成了循環(huán)引用,則這兩個對象都無法被回收。

function assignHandler() {
 var element = document.getElementById("id");
 element.onclick = function() {
 alert(element.id);
 }
}

匿名函數(shù)保存了一個對element的引用,只要匿名函數(shù)存在,element的引用數(shù)至少為1,它所占用的內(nèi)存就永遠(yuǎn)不會被回收。

function assignHandler() {
 var element = document.getElementById("id");
 var id = element.id;
 element.onclick = function() {
 alert(id);
 }
 element = null;
}

通過把element.id的一個副本保存在變量中,并且在閉包中引用該變量消除了循環(huán)引用,但是僅僅做到這一步還不能解決內(nèi)存泄漏的問題,閉包會引用包含函數(shù)的所有活動對象,包含element,即使閉包不直接引用element,包含函數(shù)的活動對象中也仍然會保存一個引用,因此有必要把element元素設(shè)置為null,這樣就能解除對DOM對象的引用,確保正?;厥掌湔加玫膬?nèi)存。

6、模仿塊級作用域

JavaScript中沒有直接的塊級作用域。

function output(count) {
 for (var i = 0; i < count; i++) {
 alert(i);
 }
 alert(i);//
輸出:10 }

使用閉包可以模仿塊級作用域——創(chuàng)建并立即調(diào)用一個函數(shù),這樣既可以執(zhí)行其中的代碼,又不會在內(nèi)存中留下對該函數(shù)的引用。結(jié)果是內(nèi)部函數(shù)的所有變量都會立即被銷毀,除非將某些變量賦值給了包含作用域(即外部作用域)中的變量。

用作塊級作用域的匿名函數(shù):將函數(shù)聲明包含在一對圓括號中,表示它實(shí)際上是一個函數(shù)表達(dá)式,緊隨其后的另一對圓括號會立即調(diào)用這個函數(shù)。

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

可以使用匿名函數(shù)表達(dá)式來模擬塊級作用域,任何定義在匿名函數(shù)中的變量在匿名函數(shù)執(zhí)行完之后都將被銷毀,在匿名函數(shù)外訪問這些變量將會產(chǎn)生錯誤。

function output(count) {
 (function() {
 for (var i = 0; i < count; i++) {
 alert(i);
 }
 }) ();
 alert(i);//出錯
}

更多關(guān)于JavaScript相關(guān)內(nèi)容可查看本站專題:《javascript面向?qū)ο笕腴T教程》、《JavaScript常用函數(shù)技巧匯總》、《JavaScript錯誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)》

希望本文所述對大家JavaScript程序設(shè)計有所幫助。

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

JavaScript閉包原理與用法實(shí)例分析

JavaScript閉包原理與用法實(shí)例分析:本文實(shí)例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下: 1、與閉包有關(guān)的兩個概念: 1) 變量的作用域 不帶有關(guān)鍵字var的變量會成為全局變量; 在函數(shù)中使用關(guān)鍵字var聲明的變量是局部變量。 局部變量只有在函數(shù)內(nèi)部才能訪問到,在函數(shù)外
推薦度:
標(biāo)簽: 使用 用法 使用方法
  • 熱門焦點(diǎn)

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 久久伊人五月天 | 国产毛片a | 国产在线欧美日韩一区二区 | 日韩 亚洲 欧美 中文 高清 | 99热只有精品一区二区 | 欧美亚洲精品在线 | 国产成人精品日本亚洲语音2 | 伊人久久精品久久亚洲一区 | 国产精品原创视频 | 日本美女逼逼 | 欧美性xxxx极品高清 | 欧美激情网站 | 国产精品视频免费观看 | 午夜影院欧美 | 国产欧美中文字幕 | 精品一区二区在线 | 欧美在线aa | 九九精品视频一区在线 | 欧美激情综合亚洲一二区 | 国产成人精品一区二三区2022 | 日本精品久久久一区二区三区 | 国产a不卡| 国产精品一区欧美日韩制服 | 精品91精品91精品国产片 | 国产精品亚洲国产三区 | 四虎91视频 | 一区二区三区高清不卡 | 欧美系列在线 | 国产在线a视频 | 亚洲欧美日韩精品永久在线 | 91精品一区二区三区久久久久 | 亚洲韩精品欧美一区二区三区 | 日韩第一页在线 | 欧美 日韩 国产在线 | 亚洲精品乱码久久久久久中文字幕 | 一区二区三区在线 | 一级毛片私人影院免费 | 国产亚洲欧美日韩综合另类 | 亚洲一区二区三区免费 | 99久久亚洲精品影院 | 国产日韩欧美亚洲综合 |