一、作用域和作用域链
当函数声明的时候,函数会通过内部属性[scope]来记录创建范围
DEMO1:
var str = '123';
function fn(){
var str = '456';
console.log( str );
}
fn();
输出结果:456
二、闭包
什么是闭包:闭包是一个函数加上到创建函数的作用域的连接,闭包“关闭”了函数的自由变量。
第一句话(得到的理解):2个函数,2个函数作用域[scope]还要连接上;
第二句话(得到的理解):关闭函数的变量自由:它暂时不会销毁;
(比如DEMO2中的变量n,DEMO3中的变量idx
因为有引用,所以不会暂时销毁,
原理:JS垃圾回收机制https://blog.csdn.net/qq_43540219/article/details/107519917)
DEMO2:
function fun(n){
return function (m){
n+=m;
return n;
}
}
//第一步
var f = fun(5);
//变量n=5,被闭包给“关闭”了(暂时不会被销毁)
/*现在f=function (m){
n+=m;//n=5
return n;
}*/
//第二步
console.log( f(1) );//执行前n=5,执行后n=6
console.log( f(1) );//执行前n=6,执行后n=7
console.log( f(1) );//执行前n=7,执行后n=8
输出结果:6 7 8
三、无意间共享环境[可以通过闭包解决](闭包的实际应用)
DEMO3:
<body>
<ul>
<li>111</li>0
<li>111</li>1
<li>111</li>2
</ul>
<script type="text/javascript">
var lis = document.getElementsByTagName('li');
for(var i=0;i<lis.length;i++){
(function(){
var idx = i;
//idx保留当前循环的i值,用闭包“关闭”idx,使其一直存在
lis[i].onclick = function(){
//当点击的时候调用外层的idx(当函数内部没有则去外层找)
//如果不这么做闭包,直接循环,则会导致所有的i都=3
//原因参考js单线程和消息队列(循环不可能等onlick事件
//否则js代码将会停在循环这里,直到onclick触发才到下一步)
console.log(idx);
}
})();
}
</script>