以前对闭包的理解比较浅,只知道一个函数里面返回另一个匿名函数就是闭包,具体怎么用一直是模模糊糊的,最近为了解决一个防止重复点击的问题,查了不少的资料,现在应该是比较清楚闭包的用法了。来代码说话吧。
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>测试函数节流</title> <style> #container{ width: 100%; height: 200px; border: 1px solid #646464; color: #000000; } </style> </head> <body > <div id="container"></div> </body>
<script>
function alertSomething(){
alert("您的鼠标正在移动");
};
document.getElementById("container").onmousemove = alertSomething;
</script>
</html>
现在鼠标在页面上的那块区域一移动就会触发一个函数,只要我不停止函数就一直会触发,但是我们想要,在多次移动只触发一次函数,这样能解决我们的调用的次数。这时代码应该是这个样子的。
var timer; function throttle(){ clearTimeout(timer); timer = setTimeout(function(){ alertSomething() },1000); }
代码看上去没什么问题,对吧!但是当你的页面已经有很多逻辑的时候,这里就不太好用了,比如说这样
var obj = null; var timer= null; var strBtn = null; var youka = null; function shake(e, oncomplete, distance, time){ if(typeof e === 'string'){ e = document.getElementById(e); } if(!time){ time = 500; } if(!distance){ distance = 5; } var originalStyle = e.style.cssText; e.style.position = 'relative'; var start = (new Date()).getTime(); animate(); function animate(){ var now = (new Date()).getTime(); var elapsed = now - start; var fraction = elapsed / time; if(fraction < 1){ var x = distance * Math.sin(fraction * 4 * Math.PI); e.style.left = x + 'px'; setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.cssText = originalStyle if(oncomplete){ oncomplete(e); } } } } function shake(e, oncomplete, distance, time){ if(typeof e === 'string'){ e = document.getElementById(e); } if(!time){ time = 500; } if(!distance){ distance = 5; } var originalStyle = e.style.cssText; e.style.position = 'relative'; var start = (new Date()).getTime(); animate(); function animate(){ var now = (new Date()).getTime(); var elapsed = now - start; var fraction = elapsed / time; if(fraction < 1){ var x = distance * Math.sin(fraction * 4 * Math.PI); e.style.left = x + 'px'; setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.cssText = originalStyle if(oncomplete){ oncomplete(e); } } } } function shake(e, oncomplete, distance, time){ if(typeof e === 'string'){ e = document.getElementById(e); } if(!time){ time = 500; } if(!distance){ distance = 5; } var originalStyle = e.style.cssText; e.style.position = 'relative'; var start = (new Date()).getTime(); animate(); function animate(){ var now = (new Date()).getTime(); var elapsed = now - start; var fraction = elapsed / time; if(fraction < 1){ var x = distance * Math.sin(fraction * 4 * Math.PI); e.style.left = x + 'px'; setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.cssText = originalStyle if(oncomplete){ oncomplete(e); } } } } function shake(e, oncomplete, distance, time){ if(typeof e === 'string'){ e = document.getElementById(e); } if(!time){ time = 500; } if(!distance){ distance = 5; } var originalStyle = e.style.cssText; e.style.position = 'relative'; var start = (new Date()).getTime(); animate(); function animate(){ var now = (new Date()).getTime(); var elapsed = now - start; var fraction = elapsed / time; if(fraction < 1){ var x = distance * Math.sin(fraction * 4 * Math.PI); e.style.left = x + 'px'; setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.cssText = originalStyle if(oncomplete){ oncomplete(e); } } } } function shake(e, oncomplete, distance, time){ if(typeof e === 'string'){ e = document.getElementById(e); } if(!time){ time = 500; } if(!distance){ distance = 5; } var originalStyle = e.style.cssText; e.style.position = 'relative'; var start = (new Date()).getTime(); animate(); function animate(){ var now = (new Date()).getTime(); var elapsed = now - start; var fraction = elapsed / time; if(fraction < 1){ var x = distance * Math.sin(fraction * 4 * Math.PI); e.style.left = x + 'px'; setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.cssText = originalStyle if(oncomplete){ oncomplete(e); } } } } function shake(e, oncomplete, distance, time){ if(typeof e === 'string'){ e = document.getElementById(e); } if(!time){ time = 500; } if(!distance){ distance = 5; } var originalStyle = e.style.cssText; e.style.position = 'relative'; var start = (new Date()).getTime(); animate(); function animate(){ var now = (new Date()).getTime(); var elapsed = now - start; var fraction = elapsed / time; if(fraction < 1){ var x = distance * Math.sin(fraction * 4 * Math.PI); e.style.left = x + 'px'; setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.cssText = originalStyle if(oncomplete){ oncomplete(e); } } } }
当然把timer设为全局是没有问题的,但是如果你的业务逻辑很复杂,代码结构很乱,对于以后的维护就会变得很困难了。所以为了以后你维护代码或者维护你代码的人,为了自己为了别人,所以我我们把方法改进了,变成这样
function throttle(func){ var timer; return function(){ var context = this; var args = arguments; clearTimeout(timer); timer = setTimeout(function(){ func.apply(context,args); },1000); } }
这样变量不会被污染,且后面维护代码的人也变得简单轻松多了,别人一看看不懂,他就会惊叹哇大神啊,然后叫你帮忙看一下,这个既装逼又提高技术的做法,何乐而不为呢?
这段代码的意思就是,设置一个定时器,当上一次函数没有完成时,先清除掉,再调用。