# 闭包
在介绍闭包之前,我们先看看是什么全局变量和局部变量
# 全局变量和局部变量
局部变量:定义在函数内部的变量(只能在内部被访问) 形参也是一种局部变量
全局变量:不在函数内部定义的变量, 就称为全局变量,全局变量在任何函数内都可以被访问和修改
假如我们在函数内部 定义了一个和外部相同名字的变量, 那么在函数内部是用的哪个变量呢?
<script>
var ccc = 5;
function inner() {
var ccc = 4;
console.log(ccc);
}
inner();
</script>
以上结果会输出4 , 因为在执行过程中, 会由内向外寻找变量的定义,所以局部变量在函数内部比全局变量更有优先被使用的权力
再看一个例子, 假如我们打印外部的ccc变量会输出什么?
<script>
var ccc = 5;
function inner() {
var ccc = 4;
}
inner();
console.log(ccc);
</script>
上面的例子会输出 5, 因为函数内部定义的变量无法被外部看到
我们再来看一个比较奇葩的例子
<script>
var ccc = 5;
function inner() {
ccc += 1;
var ccc = 4;
console.log(ccc);
}
inner();
</script>
这个例子第一次打印会输出 NaN , 第二次打印会输出 4
第二次打印好理解, 因为我们已经知道局部变量优先被使用。
第一次比较奇怪, 按道理讲, 在函数内部也应该能引用到外部的全局变量ccc,但是程序的运行结果和我们的推断相反,这是因为js语言有个比较坑的知识点;即在函数执行前,语法规定把变量的定义提升到 函数的前面。
上面的例子在运行的时候浏览器是这么理解的
<script>
var ccc = 5;
function inner() {
var ccc = undefined;
ccc += 1;
ccc = 4;
console.log(ccc);
}
inner();
</script>
这种特性就叫做函数变量提升, 把一个后面定义变量, 提升到前面,因为前面有这个地方的引用。
# 局部函数
一个函数内部也可以定义另一个函数内部
<script>
function outer() {
function inner() {
console.log("innser函数")
}
inner()
}
outer();
</script>
上面的inner() 函数只能再 outer() 函数内部调用
# 特别注意
如果不加修饰词定义一个变量的话, 此变量将被视为全局变量,即使它定义在了函数内部
<script>
function fa() {
quanju = 10;
}
fa();
console.log(quanju);
</script>
# 闭包
# 概念
从概念上讲,闭包就是一个函数以及捆绑在此函数周围环境状态的引用组合, 每创建一个函数都会产生一个闭包
这个定义比较抽象,下面,我们举个栗子
<script>
function outter(){
var cons = '常量小常'
return function() {
return cons;
}
}
// 得到外部函数的内部函数
var consFun= outter(1,2);
// 执行内部函数
consFun();
</script>
这个例子最终会输出 ‘常量小常’, 虽然内部函数是在外部执行的, 但它依然能够找到定义时候的一些常量值。这个就是一种闭包的表现形式
换句话说,就是函数在执行的时候,能够还原它定义时所处的环境,能够按照定义时候的样子去执行
# 模拟私有变量
很多语言都支持私有变量, 就是将一个变量或者方法声明为私有,只能被内部使用,外部要想使用只能通过定义的一些公共方法访问
Js原生不支持这种语法,但可以通过闭包模拟这种私有变量的特性
下面就是一个闭包模拟私有变量的例子 , privateCounter 变量不能直接被外部访问,只能通过特定的方法操作。这个例子来源于此:
用闭包模拟私有变量
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures#%E7%94%A8%E9%97%AD%E5%8C%85%E6%A8%A1%E6%8B%9F%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95
<script>
var Counter = (function () {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function () {
changeBy(1);
},
decrement: function () {
changeBy(-1);
},
value: function () {
return privateCounter;
},
};
})();
console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */
</script>