1、什么是闭包
是对js作用域特性的一种应用,因为函数内定义的局部变量不能被外部获取,而函数却可以访问到其外部作用域的变量,所以可以在其内部定义一个访问局部变量的方法,并将之输出到外部,return出去,也就是在函数销毁之后通过函数输出的方法来访问局部变量。
2、闭包的作用
先看几个栗子🌰
for (var i = 0; i < 5; ++i) { setTimeout(function() { console.log(i + " "); }, 100); }
输出结果为 5 5 5 5 5
原因: js 运行环境为单线程,setTimeout 注册的函数需要等到线程空闲时才能执行,此时 for 循环已经结束,i 值为 5,又因为循环中 setTimeout 接受的参数函数通过闭包访问变量 i,所以 5 个定时输出都是 5。
修改方法:将 setTimeout 放在立即执行函数中,将 i 值作为参数传递给包裹函数,创建新闭包。
for (var i = 0; i < 5; ++i) { (function(i) { setTimeout(function() { console.log(i + " "); }, 100); })(i); }
输出结果为: 0 1 2 3 4
function add() { var x = 1; console.log(++x); } add(); //执行输出2, add(); //执行还是输出2,
怎样才能使每次执行有加 1 效果呢?使用闭包
function add() { var x = 1; return function() { console.log(++x); }; } var num = add(); num(); //输出2, num(); //输出3, num(); //输出4,
1.模仿块级作用域
2.储存变量
3.封装私有变量
3.闭包的应用
防抖debounce
function debounce(fn,delay){ let timer = null; return function(){ let context = this let args = arguments clearTimeout(timer) timer = setTimeout(function(){ fn.apply(context,args) },delay) } } let flag = 0 function foo(){ flag++ console.log('Number of calls:%d',flag) } document.addEventListener('click',debounce(foo,1000))
节流 throttle
function throttle(fn,delay){ let timer = null; let startTime = Date.now() return function(){ let curTime = Date .now() let remaining = delay - (curTime -startTime) const context = this const args = arguments clearTimeout(timer) if(remaining<=0){ fn.apply(context,args) startTime = Date.now(); }else{ timer = setTimeout(fn,remaining) } } } function xxx(){ console.log('1') } document.addEventListener('click', throttle(xxx,5000))
setTimeout
function f1(a) { function f2() { console.log(a); } return f2; } var fun = f1(1); setTimeout(fun,1000);//一秒之后打印出1
封装私有变量
function f1() { var sum = 0; var obj = { inc:function () { sum++; return sum; } }; return obj; } let result = f1(); console.log(result.inc());//1 console.log(result.inc());//2 console.log(result.inc());//3
对于防抖和节流的理解参考:https://www.jianshu.com/p/c8b86b09daf0