闭包是什么
首先闭包他不是一个具体的东西,而是由于js代码执行时形成的一种现象.简单来说就是:闭包就是能够读取其他函数内部变量的函数
闭包详解
我们在函数内部定义了一个变量 let a = 1; 正常情况我们在函数外部是访问不到这个变量的 ,因为函数内部会形成一个局部作用域,当我们在外部访问时就回报错改变量未定义.
function foo() {
let a = 0;
}
console.log(a);// a is not defined
有一个需求,如果我们需要获取到这个变量的值怎么办呢,我们可以return这个值
function foo() {
let a = 1;
return a;
}
console.log(foo()); //1
我们获取到了 这个值,但是现在新增需求了,我们又需要修改他怎么呢,我们可以用一个变量来接这个变量,然后修改
function foo() {
let a = 1;
return a;
}
let b = foo();
b += 1;
console.log(b);
我们可以看到b成功接到a的值,而且得到了+1的值,但是又一个问题就是,函数内部的值并没有改变,所以我们需要在函数foo内部操作,才能改变 变量a的的值
function foo() {
let a = 1;
return function () {
a += 1;
return a;
};
}
console.log(foo()()); // 2
console.log(foo()()); // 2
我们可以发现我们一家成功修改了a的值,而且2次修改都是独立完成的.以上 我们就简单的完成了一个闭包.
闭包的使用
封装私有变量
function f1() {
var sum = 0;
var obj = {
inc: function () {
sum++;
return sum;
}
};
return obj;
}
let result1 = f1();
let result2 = f1();
console.log(result1.inc(), result1.inc()); // 1 2
console.log(result2.inc(), result2.inc()); // 1 2
可以看到我们封装了一个函数f1,返回了一个对象obj,对象中有一个方法inc,内部num++,然后返回num. 然后用result1和result2去接f1的返回值这个对象.可以发现result1,result2是独立的2个num值
防抖
function debounce(fn,delay){ let timer = null //借助闭包 return function() { if(timer){ clearTimeout(timer) timer = setTimeOut(fn,delay) }else{ timer = setTimeOut(fn,delay) } } } 我们常用的防抖函数,这个定时器timer就是一个闭包的变量
弊端
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
- 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。