許多模式均可以使用閉包和高階函數來實現javascript
閉包的造成與變量的做用域以及變量的生命週期密切相關java
變量的做用域,就是指變量的有效範圍。咱們最常談到的是在函數中聲明的變量做用域。node
在 JavaScript 中,函數能夠用來創造函數做用域。此時的函數像一層半透明的玻璃,在函數裏面能夠看到外面的變量,而在函數外面則沒法看到函數裏面的變量。es6
for(var i = 0;i<;i++){ nodeArr[i].oncick = function(){ alert(i) } }
點擊事件爲異步事件,在點擊時循環已完畢,故每個點擊事件都會獲得i = 5ajax
method:使用閉包把每次循環的i值封閉起來編程
for (var i =0;i<5;i++){ (nodeArr[i].onclick = funcioton(){ alert(i) })(i) }
也可以使用es6 let。let聲明封閉做用域瀏覽器
封裝變量:閉包能夠幫助把一些不須要暴露在全局的變量封裝成」私有變量「緩存
var mult = function(){ var a = 1 for (var i = 0, l=arguments.length;i<;i++){ a = a*arguments[s] } return a }
上面爲最簡易進行參數乘積的函數,接下來進行對代碼提煉封裝,以及閉包封裝緩存安全
var mult = (function(){ var cahe = {} //封裝功能函數,有助於代碼複用性,用戶計算不定個數入參乘積 var calculate = function(){ var a = 1 for (var i = 0,l=arguments.length;i<l;i++){ a = a*arguments[i] } return a } return function(){ // 將入參經過join鏈接成字符串做爲object key存入緩存中,key部分能夠擴展如 1,3,5 與3,1,5爲同一結果 var args = [].join.call(arguments,',') //若是緩存過直接返回值 if(args in cache){ return cache[args] } //將未緩存加入緩存並返回 return cache[args] = calculate.apply(null,arguments) } })()
img 對象常常用於進行數據上報,以下所示:閉包
var report = function( src ){ var img = new Image(); img.src = src; }; report( 'http://xxx.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; } })();
高階函數至少知足如下一個條件
回調函數
用於將邏輯代碼抽離
var appendDiv = function( callback ){ for ( var i = 0; i < 100; i++ ){ var div = document.createElement( 'div' ); div.innerHTML = i; document.body.appendChild( div ); if ( typeof callback === 'function' ){ callback( div ); } } }; appendDiv(function( node ){ node.style.display = 'none'; });
能夠看到,隱藏節點的請求其實是由客戶發起的,可是客戶並不知道節點何時會建立好,因而把隱藏節點的邏輯放在回調函數中,「委託」給 appendDiv 方法。appendDiv 方法固然知道節點何時建立好,因此在節點建立好的時候,appendDiv 會執行以前客戶傳入的回調函數。
3.Array.prototype.sort方法傳入一個回調做爲排序的規則,使sort成爲一個很是靈活的方法
將函數做爲返回值出,更能體現函數式編程的巧妙。讓函數返回一個可執行的函數,意味着運算過程使可延續的
判斷數據類型
用 Object.prototype.toString 來計算。Object.prototype.toString.call( obj )返回一個字符串,好比 Object.prototype.toString.call( [1,2,3] ) 老是返回 "[object Array]" , 而Object.prototype.toString.call( 「str」)老是返回"[object String]"。
//經過return一個函數接收外部函數傳入的參數,進行參數的嵌套, var isType = function( type ){ return function( obj ){ return Object.prototype.toString.call( obj ) === '[object '+ type +']'; } }; //接收第一個參數賦值不一樣類別的判斷器 var isString = isType( 'String' ); var isArray = isType( 'Array' ); var isNumber = isType( 'Number' ); //接收第二個參數進行運算 console.log( isArray( [ 1, 2, 3 ] ) );
Function.prototype.before = function( beforefn ){ var __self = this; // 保存原函數的引用 return function(){ // 返回包含了原函數和新函數的"代理"函數 beforefn.apply( this, arguments ); // 執行新函數,修正 this return __self.apply( this, arguments ); // 執行原函數 } }; Function.prototype.after = function( afterfn ){ var __self = this; return function(){ var ret = __self.apply( this, arguments ); afterfn.apply( this, arguments ); return ret; } }; var func = function(){ console.log( 2 ); }; func = func.before(function(){ console.log( 1 ); }).after(function(){ console.log( 3 ); }); func();