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