本文原創:yuanlan前端
var isType = function(type){ return function(obj){ return Object.prototype.toString.call(obj) === '[object '+type+']'; } } 複製代碼
單例模式:ajax
var getSingle = function(fn){ var res; return function(){ return res || (res = fn.apply(this,arguments)); } } var getStr = getSingle(function(){ return new String('123') }); var str1 = getStr(); var str2 = getStr(); console.log(str1===str2); //true 複製代碼
Function.prototype.before = function(brforeFn){ var self = this; return function(){ brforeFn.apply(this, arguments); 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; } } 複製代碼
主要應用:編程
1.防止window.onload被二次覆蓋瀏覽器
window.onload = function(){ console.log(1); console.log(2); } 複製代碼
直接修改原始的代碼,徹底侵入式編程bash
改進:markdown
var _onload = window.onload; window.onload = function(){ if(_onload){ _onload(); } console.log(2); } 複製代碼
多出來一個變量,增長了額外的成本閉包
再次改進:app
window.onload = (window.onload || function(){}).after(function(){ console.log(2); }) 複製代碼
2.統計日誌上報dom
例如統計一下1000個dom插入body所花的時間函數
var createDom = function(){ var start = new Date().getTime(); // 屬於時間統計,與業務沒有關係 for(var i=0;i<1000;i++){ var oDiv = document.createElement('div'); oDiv.innerHTML = i; document.body.appendChild(oDiv); } var time = new Date().getTime() - start;// 屬於時間統計,與業務沒有關係 console.log('createDom:' + time);// 屬於時間統計,與業務沒有關係 } 複製代碼
能夠刪除這些統計的代碼,定義一個通用的包裝器
var logTime = function(fn,fn_name){ return fn = (function(){ var start; return fn.before(function(){ start = new Date().getTime(); }).after(function(){ var time = new Date().getTime() - start; console.log(fn_name+':'+time); }) })(); } createDom = logTime(createDom,'createDom'); createDom(); 複製代碼
又稱部分求值 首先會接收一些參數。接收了參數以後並不會當即求值,而是繼續返回另一個函數,剛纔傳入的參數在函數造成的閉包中被保存起來。待到函數真正求值的時候,以前傳入的參數都會被一次性用於求值。
var currying = function(fn){ var args = []; var f = function(){ if(arguments.length === 0){ return fn.apply(this, args) }else{ [].push.apply(args,arguments); return f; } } return f; } var costFn = (function(){ var res = 0; return function(){ for(var i=0,len = arguments.length;i<len;i++){ res+=arguments[i]; } return res; } })(); var costCur = currying(costFn); console.log(costCur(100)); //[Function: f] console.log(costCur(200)); //[Function: f] console.log(costCur(300)); //[Function: f] console.log(costCur()); //600 複製代碼
借用其餘對象的方法
Function.prototype.uncurrying = function(){ var self = this; //self : Array.prototype.push return function(){ var obj = Array.prototype.shift.call(arguments); //obj: {'length':0,'0':1} return self.apply(obj,arguments);//Array.prototype.push.apply(obj,[2]); } } 複製代碼
Function.prototype.uncurrying = function(){ var self = this; return function(){ return Function.prototype.call.apply(self,arguments); } } 複製代碼
var throttle = function(fn,interval){ var self = fn, timer, firstTime = true; return function(){ var that = this, args = arguments; if(firstTime){ //若是第一次被調用,不須要延遲 self.apply(that, args); firstTime = false; return; } if(timer){ //若是定時器還在,說明前一次的延遲執行尚未完成 return; } timer = setTimeout(function(){ clearTimeout(timer); timer = null; self.apply(that, args) },interval || 500); } } var throttle2 = function(fn,interval){ var self = fn, firstTime = true, pre; return function(){ var that = this, args = arguments; if(firstTime){ //若是第一次被調用,不須要延遲 self.apply(that, args); firstTime = false; pre = new Date().getTime(); return; } var now = new Date().getTime(); if(now - pre > interval){ pre = now; self.apply(that, args); } } } window.onresize = throttle(function(){ console.log(new Date()); },1000); 複製代碼
有些函數確實須要調用屢次。例如手動建立一個用戶數量很大的用戶列表,這樣形成短期在頁面添加大量的dom元素節點,這樣對瀏覽器的性能形成很大影響,形成瀏覽器卡頓甚至卡死的現象。 解決方法:寫一個函數建立節點的工做分批執行,例如200ms建立8個。
下面是一個通用的分時函數
var timeChunk = function(ary,fn,count){ count = count || 1; var timer; var start = function(){ for(var i=0,len=Math.min(count,ary.length);i<len;i++){ var obj = ary.shift(); fn(obj); } }; return function(){ timer = setInterval(function(){ if(ary.length===0){ clearInterval(timer); return; } start(); },200); } } 複製代碼
有些函數用到的時候只讓它進行加載一次。 好比,瀏覽器的兼容性致使有些方法是不一致的,因此瀏覽器的嗅探工做是不可避免的。
例如經常使用的事件綁定函數。
var addEvent = function(ele,type,handler){ if(window.addEventListener){ return ele.addEventListener(type,handler,false); }else if(window.attachEvent){ return ele.attachEvent('on'+type,handler); } } 複製代碼
缺點是每次執行的時候都會執行一次if分支,形成了一些沒有沒必要要的浪費。
改進:把嗅探工做提到代碼加載的時候,在代碼加載的時候就進行一次判斷,這樣使用屢次也會只有一次判斷了。
var addEvent = (function(){ console.log('addEvent enter') if(window.addEventListener){ return function(ele,type,handler){ ele.addEventListener(type,handler,false); } }else if(window.attachEvent){ return function(ele,type,handler){ ele.attachEvent('on'+type,handler); } } })(); 複製代碼
缺點是若是頁面沒有使用到addEvent函數,這樣就形成了浪費,提早嗅探瀏覽器的操做屬於多餘。
改進:使用惰性加載函數。
var addEvent = function(ele,type,handler){ if(window.addEventListener){ addEvent = function(ele,type,handler){ ele.addEventListener(type,handler,false); } }else if(window.attachEvent){ addEvent = function(ele,type,handler){ ele.attachEvent('on'+type,handler); } } return addEvent; } 複製代碼
這就是惰性載入函數。addEvent被聲明爲一個普通函數,在進入判斷的時候,addEvent被重寫。在下一次進來的時候addEvent函數就不會存在條件分支的語句了。
歡迎計算機前端相關領域小夥伴加入咱們,具體的招聘信息可進入公衆號查看,歡迎關注。
本文由博客一文多發平臺 OpenWrite 發佈!