深入理解闭包系列第五篇——闭包的10种形式
前面的話
根據閉包的定義,我們知道,無論通過何種手段,只要將內部函數傳遞到所在的詞法作用域以外,它都會持有對原始作用域的引用,無論在何處執行這個函數都會使用閉包。接下來,本文將詳細介紹閉包的10種形式
?
返回值
最常用的一種形式是函數作為返回值被返回
var F = function(){var b = 'local';var N = function(){return b;}return N; } console.log(F()());?
函數賦值
一種變形的形式是將內部函數賦值給一個外部變量
var inner; var F = function(){var b = 'local';var N = function(){return b;};inner = N; }; F(); console.log(inner());?
函數參數
閉包可以通過函數參數傳遞函數的形式來實現
var Inner = function(fn){console.log(fn()); } var F = function(){var b = 'local';var N = function(){return b;}Inner(N); } F();?
IIFE
由前面的示例代碼可知,函數F()都是在聲明后立即被調用,因此可以使用IIFE來替代。但是,要注意的是,這里的Inner()只能使用函數聲明語句的形式,而不能使用函數表達式。詳細原因移步至此
function Inner(fn){console.log(fn()); }(function(){var b = 'local';var N = function(){return b;}Inner(N); })();?
循環賦值
在閉包問題上,最常見的一個錯誤就是循環賦值的錯誤。關于其錯誤原因的詳細解釋移步至此
function foo(){var arr = [];for(var i = 0; i < 2; i ){arr[i] = function(){return i;}}return arr; } var bar = foo(); console.log(bar[0]());//2正確的寫法如下
function foo(){var arr = [];for(var i = 0; i < 2; i ){arr[i] = (function fn(j){return function test(){return j;}})(i);}return arr; } var bar = foo(); console.log(bar[0]());//0?
g(s)etter
我們通過提供getter()和setter()函數來將要操作的變量保存在函數內部,防止其暴露在外部
var getValue,setValue; (function(){var secret = 0;getValue = function(){return secret;}setValue = function(v){if(typeof v === 'number'){secret = v;}} })(); console.log(getValue());//0 setValue(1); console.log(getValue());//1?
迭代器
我們經常使用閉包來實現一個累加器
var add = (function(){var counter = 0;return function(){return counter; } })(); console.log(add())//1 console.log(add())//2類似地,使用閉包可以很方便的實現一個迭代器
function setup(x){var i = 0;return function(){return x[i ];} } var next = setup(['a','b','c']); console.log(next());//'a' console.log(next());//'b' console.log(next());//'c'?
區分首次
var firstLoad = (function(){var _list = [];return function(id){if(_list.indexOf(id) >= 0){return false;}else{_list.push(id);return true;}} })();firstLoad(10);//true firstLoad(10);//false firstLoad(20);//true firstLoad(20);//false?
緩存機制
通過閉包加入緩存機制,使得相同的參數不用重復計算,來提高函數的性能
未加入緩存機制前的代碼如下
var mult = function(){var a = 1;for(var i = 0,len = arguments.length; i<len; i ){a = a * arguments[i];}return a; }加入緩存機制后,代碼如下
var mult = function(){var cache = {};var calculate = function(){var a = 1;for(var i = 0,len = arguments.length; i<len; i ){a = a * arguments[i];}return a;};return function(){var args = Array.prototype.join.call(arguments,',');if(args in cache){return cache[args];}return cache[args] = calculate.apply(null,arguments);} }()
?
img對象
img對象經常用于數據上報
var report = function(src){var img = new Image();img.src = src; } report('http://xx.com/getUserInfo');但是,在一些低版本瀏覽器中,使用report函數進行數據上報會丟失30%左右的數據,也就是說,report函數并不是每一次都成功地發起了HTTP請求
原因是img是report函數中的局部變量,當report函數的調用結束后,img局部變量隨即被銷毀,而此時或許還沒來得及發出HTTP請求,所以此次請求就會丟失掉
現在把img變量用閉包封閉起來,就能解決請求丟失的問題
var report = (function(){var imgs = [];return function(src){var img = new Image();imgs.push(img);img.src = src;} })() report('http://xx.com/getUserInfo');?
更多專業前端知識,請上 【猿2048】www.mk2048.com
總結
以上是生活随笔為你收集整理的深入理解闭包系列第五篇——闭包的10种形式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NodeJS学习目录
- 下一篇: BOM之navigator对象和用户代理