定义:
在一个函数内部的函数,可以使用其他函数的变量。
闭包是一种保护私有变量的机制,函数执行时形成私有作用域,保护私有变量不受外界影响。
外部函数调用之后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象
// 闭包实现全局变量效果
var countFn = (function(){
var count = 0;
return function(){
return count += 1;
}
})()
countFn() // count = 1;
countFn() // count = 2;
countFn() // count = 3;
优缺点:
- 优点:私有变量的存在、长期内存存储、避免全局污染
- 缺点:内存浪费、常驻内存及其使用不当的无效内存增大内存使用量,导致内存泄漏
(function immediateA(a) {
return (function immediateB(b) {
console.log(a); // => ? a = 0
})(1);
})(0);
// 0
let count = 0;
(function immediate() {
if (count === 0) {
let count = 1;
console.log(count); // 输出什么?
}
console.log(count); // 输出什么?
})();
// 1 0
for (var i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // => ?
}, 1000);
}
// 3 3 3
阶段1:for()重复3次,在每次循环都会创建一个新函数log(),该函数将捕获变量i,setTimeout()安排log()1000ms后执行,当for()循环完成时,变量i的值为3
阶段2:1000ms后,setTimeout()执行log()函数,log()读取变量i为3,并输出3
function createIncrement() {
let count = 0;
function increment() {
count++;
}
let message = `Count is ${count}`;
function log() {
console.log(message);
}
return [increment, log];
}
const [increment, log] = createIncrement();
increment();
increment();
increment();
log(); // => ?
// count is 0
increment()被调用3次,count为3
message变量存在于createIncrement函数的作用域内,其初始值为'count is 0',即使count变量增加了,message也始终为'count is 0'
function createIncrement() {
let count = 0;
function increment() {
count++;
}
increment();//这里调用n次 message里的count会+n
let message = `Count is ${count}`;
function log() {
console.log(message);
}
return [increment, log];
}
const [increment, log] = createIncrement();
increment();
increment();
increment();
log(); // => count is 1
闭包的应用场景
函数节流
var timer = null;
window.onresize = function(){
clearTimeout(timer);
timer = setTimeout(function(){
console.log(document.documentElement.clientWidth);
},500)
}
// 使用闭包实现函数节流
function throttle(fn,delay){
var timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(fn,delay);
}
}
window.onresize = throttle(function(){
console.log(document.documentElement.clientWidth);
},400)
自执行函数
(function(){
var name = 'zhangsan';
var fn1 = function(){
return name
}
fn2(fn1);
})()
function fn2(f){
console.log(f());
}
循环赋值
for(var i=1;i<=10; i++){
(function(j){
setTimeout(function(){
console.log(j)
},j*1000)
})(i)
}
函数防抖
function debounce(callback,time){
var timer;
return function(){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(()=>{
callback();
},time)
}
}
window.onresize = debounce(()=>{console.log(1)},500)