1.函数执行,形成一个私有的执行上下文EC(XX)
- 保护作用:在这个上下文中会有一些私有的变量AO(XX),这些私有的变量和外界的变量不会冲突(互不影响)
- 保存作用:某些情况下,上下文中的某些内容被外部占用后,当前上下文并不会出栈销毁,这样就会把上下文中的一些信息存储起来
2.利用闭包的保护作用
- 1.团队协作开发中,A/B共同开发一个页面,最后要把代码合并在一起,为了防止全局变量的冲突污染,我们建议每个开发者,都把自己的代码放置到一个闭包中(自执行函数执行即可,这样就是私有的上下文)保护起来
- 2.如果我们是封装一个插件或者类库等,为了防止我们定义的变量和方法 和 用户定义的冲突,我们也是需要把所有写的代码放到一个闭包中,例如:jQuery...
3.市面上理解的闭包
- 其实,函数执行会形成一个私有上下文的机制就被称为“闭包”,只不过市面上认为,一般的上下文执行完就出栈销毁了,只有那些没有被销毁的上下文才能被称为“闭包”
4.闭包的写法()()
-
1、自执行函数的写法:函数前面加() ~ ! - + ;
- +不太合适; -
2.小组开发:各自形成一个闭包
//A的代码: (function anonymous() { //=>自执行函数执行,会形成一个私有的上下文 //=>在这里声明+定义的变量或者函数都是私有的 var x = 100, y = 200; function func() { // ... } })();
//B的代码: ~ function anonymous() { // console.log(anonymous); //=>函数本身匿名函数设置的函数名只能在函数里面应用 //=>函数外面是无法访问的 var x = 200, n = 0;
function func() { // ... }
function handled() { // ... } }(); console.log(anonymous); //=>(自执行函数,把函数用闭包保护起来,所以外面不能使用) //=>Uncaught ReferenceError:
5.选项卡
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!-- IMPORT CSS -->
<link rel="stylesheet" href="reset.min.css">
<style>
.tabBox {
margin: 60px auto;
width: 500px;
}
.tabBox .tab {
position: relative;
top:-36px;
}
.tabBox .tab li {
float: left;
margin-right: 10px;
padding: 0 10px;
height: 35px;
line-height: 35px;
font-size: 14px;
border: 1px solid #AAA;
background: #f6f7fb;
cursor: pointer;
}
.tabBox .tab li.active {
background: #FFF;
border-bottom-color: #FFF;
}
.tabBox div {
display: none;
padding: 10px;
height: 100px;
border: 1px solid #AAA;
background: #FFF;
}
.tabBox div.active {
display: block;
}
</style>
</head>
<body>
<section class="tabBox" id="tabBox">
<ul class="tab clearfix">
<li class="active">编程</li>
<li>读书</li>
<li>运动</li>
</ul>
<div class="active">编程可以使我“赚取高薪”</div>
<div>读书可以使我“修身养性”</div>
<div>运动可以使我“身体健康”</div>
</section>
<!-- IMPORT JS -->
<script>
var tabBox = document.getElementById('tabBox'),
navList = tabBox.getElementsByTagName('li'),
conList = tabBox.getElementsByTagName('div');
// changeTab:实现页卡切换的方法
function changeTab(index) {
// index存储的是当前点击这一项的索引
for (var i = 0; i < navList.length; i++) {
navList[i].className = '';
conList[i].className = '';
}
navList[index].className = 'active';
conList[index].className = 'active';
}
//1、let实现:闭包的保存作用
// for (let i = 0; i < navList.length; i++) {
// // 利用ES6中块上下文(作用域)的概念,每一轮循环都会形成一个私有的上下文,里面记录了私有变量的i,i的值分别是每一轮循环的结果 0/1/2...
// navList[i].onclick = function () {
// changeTab(i);
// };
// }
//2、 自执行函数:利用闭包的保存作用:形成一个不被释放的私有上下文(这种方式是不好的,因为循环多少次,就形成多少个不销毁的上下文,很消耗性能,真实项目中是不推荐使用的)
// for (var i = 0; i < navList.length; i++) {
// navList[i].onclick = (function (i) {
// // i也是闭包中的私有变量
// return function () {
// changeTab(i);
// }
// })(i); // i是每一轮循环全局下的i
// }
/*
i=0 第一轮循环
navList[0].onclick = (function (n) {
自执行函数执行,形成一个私有的上下文EC(AN1) [此上下文不会销毁]
作用域链:<EC(AN1),EC(G)>
形参赋值:n=0
变量提升:--
代码执行:
//=>return BBBFFF000;
return function () {
changeTab(n);
}
})(i); //=>把当前全局变量i的值作为实参传递给自执行函数 ...(0)
navList[0].onclick=BBBFFF000;
i=1 第二轮循环
navList[1].onclick = (function (n) {
自执行函数执行,形成一个私有的上下文EC(AN2) [此上下文不会销毁]
作用域链:<EC(AN2),EC(G)>
形参赋值:n=1
变量提升:--
代码执行:
//=>return BBBFFF111;
return function () {
//=>点击哪一个LI就会把它绑定的办法执行,也会形成私有上下文EC(LI2)
// 作用域链:<EC(LI2),EC(AN2)>
// 形参赋值:--
// 变量提升:--
// 代码执行:
changeTab(n); //=>n不是私有变量,是EC(AN2)中的1
}
})(1);
navList[1].onclick=BBBFFF111;
......
循环结束后,全局i=3;这一套循环结束,我们每一轮循环都创建了一个不销毁的私有上下文(闭包):EC(AN1)~EC(AN3),而且每一个闭包中都有一个私有变量n,存储的是本轮循环全局i的值(EC(AN1)中的n=0 EC(AN1)中的n=1 ...)
*/
//3、[].forEach.call 这种方案的原理就是闭包,和自执行函数的原理是一样的
// [].forEach.call(navList, function (item, index) {
// item.onclick = function () {
// changeTab(index);
// }
// });
//4.循环绑定点击事件(基于自定义属性解决循环事件绑定中索引i的问题)
for (var i = 0; i < navList.length; i++) {
navList[i].index = i;
navList[i].onclick = function () {
changeTab(this.index);
};
}
</script>
</body>
</html>