Javascript的闭包及其使用技巧实例
Javascript的閉包及其使用技巧實(shí)例
一、閉包的基本概念
閉包(Closure)是一個(gè)引用了自由變量的函數(shù),記錄了該函數(shù)在定義時(shí)的scope chain。又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures).
閉包的基本規(guī)則:
* 函數(shù)執(zhí)行是基于函數(shù)定義時(shí)的scope, 而不是 函數(shù)運(yùn)行時(shí)的scope
(定義時(shí)的Scope: 在定義這個(gè)函數(shù)的時(shí)候的scope chain)
?
為此, JS的function對(duì)象的內(nèi)部狀態(tài),不僅包括函數(shù)代碼本身, 而且包括了一個(gè)引用,指向函數(shù)定義時(shí)的scope Chain,
后者,用于提供函數(shù)中變量的值, 這種把代碼及其所需要的scope組合到一起, 就是 閉包,closure。它是JS許多實(shí)用技巧的技術(shù)基礎(chǔ)。
?
二、閉包的應(yīng)用實(shí)例?
示例1:
var who = "global scope"; // 全局變量who
function checkscope() {??
??? var who = "local scope"; // 局部變量who
??? function f() { return who; } // 嵌套函數(shù),
??? return f();
}
checkscope(); ? ? ? ? ? ? ? ? ?// => "local scope"
?
f函數(shù)在定義的時(shí)候, scope chain中有局部變量who和全局變量who, 按照局部變量優(yōu)先于全局變量的原則,
? ?函數(shù)中的who的應(yīng)該局部變量這的who,其值是 “l(fā)ocal scope”。
這就是函數(shù)的定義時(shí)Scope。根據(jù)Clouse的特性,JS會(huì)記錄這些信息,?不論這個(gè)函數(shù)f在什么地方執(zhí)行, who的值都是這個(gè)“l(fā)ocal scope”
?
示例2:執(zhí)行的地方變了, 但是函數(shù)定義時(shí)的scope未變
var who = "global scope"; // A global variable
function checkscope() {
var who = "local scope"; // A local variable
??? function f() { return who; } // Return the value in scope here
??? return f;
}
checkscope()() // => "local scope", 雖然,在這個(gè)時(shí)候“運(yùn)行時(shí)的scope”中的who已經(jīng)是全局的了。
?
實(shí)例3: 定義一個(gè)函數(shù), 每調(diào)用一次, 獲取一個(gè)唯一的整數(shù),而且從0開始遞增,每次+1。
var uniqueInteger = (function() { // 定義并執(zhí)行1個(gè)外層函數(shù)。
????????????? var counter = 0; // 根據(jù)“定義時(shí)的scope”原則, 這個(gè)變量事實(shí)上成了下面函數(shù)的私有變量, 雖然它在函數(shù)體外,
????????????? ??????????????????? 當(dāng)外層函數(shù)返回的時(shí)候, 此變量只能被下面的嵌套函數(shù)存取,
????????????? return function() { return counter++; }; // 定義一個(gè)函數(shù),稱作嵌套函數(shù),被輸出給uniqueInteger,在外面使用, 不是在外層函數(shù)內(nèi)使用。
}());
?
uniqueInteger();? // 0
uniqueInteger();? // 1
uniqueInteger();? // 2
uniqueInteger();? // 3
?
實(shí)例4: 帶有reset的計(jì)數(shù)器
function Counter() { // 定義并執(zhí)行1個(gè)外層函數(shù)。
????????????? var n = 0; // 根據(jù)“定義時(shí)的scope”原則, 這個(gè)變量事實(shí)上成了下面2個(gè)嵌套函數(shù)的私有變量, 雖然它在函數(shù)體外,
????????????? ??????????????????? 當(dāng)外層函數(shù)返回的時(shí)候, 此變量只能被下面的嵌套函數(shù)存取,
????????????? return {? // 定義2個(gè)嵌套函數(shù),并組合成1個(gè)對(duì)象輸出, 供外面使用;
????????????? ????????? // 這兩個(gè)嵌套函數(shù), 都可以存取外層函數(shù)中的局部變量n
????????????? ? count: function() { return n++; }; 。
????????????? ? reset: function() { n = 0; }
????????????? }
};
?
var counter1 = Counter(),? // 每一次調(diào)用 外層函數(shù)Counter(),都創(chuàng)建1個(gè)新的scope chain和1個(gè)新的私有變量n,互相不影響
??? counter2 = Counter();
?
counter1.count();? // 0
counter1.count();? // 1
counter1.count();? // 2
counter2.count();? // 0
counter2.count();? // 1
counter2.count();? // 2
?
counter1.reset();
counter1.count();? // 0
counter1.count();? // 1
counter2.count();? // 3
counter2.count();? // 4
?
實(shí)例5: 與Ajax調(diào)用配合使用, 顯示加載的過程和結(jié)果
<div></div>
<script src="jquery.js"></script>
<script>
??? var elem = jQuery("div");
??? elem.html("Loading...");
??? jQuery.ajax({
??????? url: "test.html",
??????? success: function(html){? //嵌入函數(shù), 直接使用外層函數(shù)中的elem, 暴露給Ajax作為callback使用
??????????? assert( elem, "The element to append to, via a closure." );
??????????? elem.html( html );
??????? }
??? });
</script>
?
實(shí)例6: 與timer配合使用, 顯示動(dòng)畫
<div id="box" style="position:absolute;">Box!</div>
<script>
var elem = document.getElementById("box");
var count = 0;
var timer = setInterval(function(){ //嵌入函數(shù), 直接使用外層函數(shù)中的elem和count, 暴露給Timer作為callback使用
??? if ( count < 100 ) {
??????? elem.style.left = count + "px";
??????? count++;
??? } else {
??????? clearInterval( timer );
??? }
}, 10);
</script>
?
進(jìn)階: ?JS 引擎內(nèi)部是如何實(shí)現(xiàn)Scope Chain和Clouse的?
Scope Chain是一個(gè)list, 不是stack,
當(dāng)執(zhí)行function的時(shí)候, 建立1個(gè)新scope object,來存儲(chǔ)此函數(shù)中的局部變量,并且把這個(gè)object加入到scope chain中,
當(dāng)推出function的時(shí)候, 從scope chain中,刪除這個(gè)object。
?
如果沒有嵌套的函數(shù), 則此object再無引用, 所以它會(huì)被 當(dāng)作垃圾收集
如果有嵌套的函數(shù), 則每一個(gè)嵌套函數(shù)都引用scope chain, 而scope chain引用此object,
** 如果這些嵌套函數(shù),只限于在其外層函數(shù)里面使用, 則 這些嵌套函數(shù)及此object仍然可以被正常地垃圾收集。
** 如果這些嵌套函數(shù) 被用于外層函數(shù)之外的更多地方, 則這些嵌套函數(shù)及此object不能正常地垃圾收集, 從而可能導(dǎo)致造成內(nèi)存泄露,
轉(zhuǎn)載于:https://www.cnblogs.com/GameEngine/p/6427232.html
總結(jié)
以上是生活随笔為你收集整理的Javascript的闭包及其使用技巧实例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Bootstrap中模态框多层嵌套时滚动
- 下一篇: DSOframer注册使用说明