JavaScript闭包问题的理解
今天早上打开B站看见一道关于JavaScript闭包的题,看了看,发现自己不太理解闭包,所以就查阅资料和思考来理解一下闭包~(最后会加上那个题的!)
关于对JavaScript闭包问题的理解
一、变量作用域
理解闭包之前,一定要理解变量作用域,JavaScript 变量可以是局部变量或全局变量。
- 全局变量
- 局部变量
- 全局变量
函数可以访问由函数内部定义的变量
var a = 4;
function myFunction() {
return a * a;
}
- 局部变量
函数可以访问函数外部定义的变量
function myFunction() {
var a = 4;
return a * a;
}
二、那么什么是闭包呢
闭包是指有权访问另一个函数作用域中的变量的函数。也就是说,闭包可以让你从内部函数访问外部函数作用域。
为什么要闭包?
优点:
- 闭包使外部得以访问函数内部的变量。
- 避免全局变量的使用,防止全局变量污染(匿名函数)。
- 让某些关键变量得以常驻内存,免于被回收销毁(闭包函数)内部函数保留了对外部函数的活动便利的引用,所以变量不会被释放。一些不经常变动计算起来又比较复杂的值保存起来,节省每次的访问时间。
- 封装私有变量,我们可以把函数当做一个范围,函数内部的变量就是私有变量,在外部无法访问,但是我们可以通过闭包的特点来访问私有变量。
缺点:
-
会造成内存泄漏:有一块内存空间被长期占用,而不被释放
-
导致变量不会被垃圾回收机制回收,造成内存消耗
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。直观的说就是形成一个不销毁的栈环境
三、那么如何从外部读取全局变量呢
正常情况下,外部是没有办法访问局部变量的,但是我们有时候需要得到函数内部的局部变量,那么此时我们该如何做?
方法:我们可以在函数的内部,再定义一个函数
function foo() {
var a = 123
function bar() {
console.log(a);
}
bar()
}
foo(); // 123
- bar在foo内部, 此时foo内部的所有的局部变量对bar都是可见的
- 但是bar内部的局部变量却是对foo不可见
- 其实这是JavaScript特有的‘链式作用域’结构,(它是就近原则,子对象会一级一级的向上寻找所有父对象的变量),因此,父对象的所有变量,对子对象都是可见的,反之则不成立
从上面的那个例子我们可以看出,bar可以获取foo中的局部变量,那么我们可以思考,要是把bar作为返回值,我们是不是可以在foo外部读取它的局部变量呢
下面这个例子:
function foo() {
var a = 123
function bar() {
console.log(a);
}
return bar;
}
var p = foo();
p(); //123
- 从上面我们可以得出,函数内返回函数是可以获取它的上一级函数的局部变量,这就是闭包问题。
四、闭包的注意事项
- 通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。
- 但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止,因为闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收。这是优点也是缺点,不必要的闭包只会徒增内存消耗,
- 所以我们在使用的时候需要注意这方面。可以通过设置null手动释放对闭包的引用。
在B站上看到的那个闭包题
//以下的代码执行后,console输出的答案是?
function fun() {
var i = 0;
return function () {
console.log(i++);
};
}
var f1 = fun();
var f2 = fun();
f1();
f1();
f2();
所以答案是什么呢?
0
1
0
其实很简单嘿嘿
f1 f2 产生闭包,各自保存一份变量i,每调用一次函数,输出i的值,然后执行i++。注意:输出时i的值为还没加1,输出后i的值才加1。 i++ 与 ++i 的区别
关于闭包其实还会涉及很多东西,鉴于我现在知识体系较薄,后续遇到问题,会继续研究哒~