Hello,这里是Kiangkiang!
闭包是面试中高频出现的一个面试题,所以今天就好好来讲一讲闭包,希望对你有用。
插播:我会持续更新有关前端的自己整理的知识和面试题,关注我,以防找不到我hhh
1.首先分清除 “闭包” 和 “闭包函数” 的定义:
闭包:内部函数总是有权访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
闭包函数:声明在一个函数中的函数,叫做闭包函数。
2.要理解闭包就要先理解变量的作用域:(懂的人跳过这部分)
在JS中存在两种变量的作用域: (1)全局变量 (2)局部变量
两种变量的区别: 函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。
举例
var a = 10;
function fn1(){
console.log(a); //输出结果:10 所以可以读取函数外部的全局变量a
var b = 20;
//console.log(c); //暂时注释掉这一行,请大家注意一下,等下说明!!!
function fn2(){
var c = 30;
console.log(a); //输出结果:10 所以可以读取函数外部(即fn1外部)的全局变量a的值
console.log(b); //输出结果是:20 所以可以读取函数外部(即fn1内部)b变量的值
};
return fn2();
};
fn1();
运行结果
注意,接下来把console.log(c);这一行取消注释。再运行,结果如下:
紫色圈的意思是,c没有定义,也就是没有定义这个变量。
但是,我们在fn2函数里面定义了,那为啥还说没定义呢?现在就是这个问题,因为fn2函数里面定义的变量是局部变量,只能在这个函数里面用,或者给fn2函数里面的函数使用,但是我们本例题fn2函数里面已经没有函数了。
然而我们本例子,我们调用c的时候是在fn2函数外部,也就是在fn1内部调用的c,因为c是局部变量,所以我们读取不到,所以就会报错:c is not defined
ok,到这里,相信你已经弄得懂局部变量和全局变量了。
那么接下来继续说闭包的问题。
3.闭包的特点
1、让外部访问函数内部变量成为可能
2、局部变量会常驻在内存中
3、可以避免使用全局变量,防止全局变量污染
4、会造成内存泄漏(有一块内存空间被长期占用,而不被释放)
闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,并且互不干扰。
闭包会发生内存泄漏,每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址。
例子
var a = 10;
function fn1(){
console.log(a); //输出结果:10 所以可以读取函数外部的全局变量a
var b = 20;
//console.log(c); //暂时注释掉这一行,请大家注意一下,等下说明!!!
function fn2(){
var c = 30;
console.log(a); //输出结果:10 所以可以读取函数外部(即fn1外部)的全局变量a的值
console.log(b); // 代号:内部b //输出结果是:20 所以可以读取函数外部(即fn1内部)b变量的值
};
return fn2();
};
console.log(b) // 代号:外部b
fn1();
通过此例子讲闭包的第一个特点:”让外部访问函数内部变量成为可能“。
注意上面的代码多加了一条语句:console.log(b)
大家可以知道,代号:外部b 这一行输出结果是b is not defined 。得不到b的值
但是闭包的特点就是 让外部访问函数内部变量成为可能, 所以我们调用fn1()函数,就可以读取出b的值了。
大家好好揣摩一下。
例子
function addCount(){
var count = 0;
return function(){
count += 1;
console.log(count);
}
}
var fun1 = addCount();
var fun2 = addCount();
fun1(); //1
fun1(); //2
fun1(); //3
fun2(); //1
fun2(); //2
通过此例子,我们讲一下闭包的另一个特点:“闭包会发生内存泄漏,每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址。”
大家也好好揣摩,一定可以明白。
ok,暂时写到这里,后续还会完善本篇文章。