# 在什么场合下用 - 1、保护变量;用自运行的匿名函数来实现; - 2、协调异步代码;自运行的匿名函数来实现,并且传参进去(异步代码需要用到原来的变量,通过作为函数的参数传进去;);   实例 Document

0000

1111

2222

3333

4444

上面的也可以改造成这样的;[也是闭包的应用] for (i = 0; i < oPs.length; i++) { oPs[i].onclick = function (i) { return function(){console.log(i);} }(i) } 高程三上说一个函数里面返回一个函数,这样是才叫闭包;(个人认为闭包是一种机制;是一个封闭的作用域;只有形成封闭作用域都可以叫做闭包的);上面就是高程上说的标准闭包写法; 但是闭包的性能其实没有自定义属性好;可以用自定义属性来写;下面是用自定义属性的写法来做的; for (i = 0; i < oPs.length; i++) { oPs[i].index=i; oPs[i].onclick = function () { console.log(this.index); } } ##### 关于作用域/闭包的其它理解; var name = "china"; var age = 5000; (function (name, age) {//形参变量也是私有作用域中的私有变量 name = "zhu"; age = 17; alert("zz"); console.log(name, age); })(name, age);//执行函数传递参数值,它只是把全局的name和age的值分别的赋值给我们的形参 ->"执行的时候传递的永远是一个值" alert("22") console.log(name, age);//先执行自执行函数,然后再执行此行 在函数里面修改全局的name和age(前提是私有的name和age依然存在) var name = "china"; var age = 5000; (function (name, age) { name = "zhu"; age = 17; //把全局的也修改为"zhu"、7 ->在私有作用域中通过指定前缀来强行的修改的全局下的值 window.name = name; window.age = age; })(name, age); console.log(name, age);//zhu ,17 jQuery部分实现的原理:在私有中定义jQuery,通过window.xxx让其在全局下也可以使用 (function () { var jQuery = function () { console.log("核心代码"); }; window.jQuery = window.$ = jQuery; })(); jQuery(); $(); ##### 闭包用在选项卡等效果上 var banner = document.getElementById("banner"); var tip = document.getElementById("tip"); var oDivs = banner.getElementsByTagName("div"); var oLis = tip.getElementsByTagName("li"); //鼠标滑过某一个li,我们让所有的li和所有的div都没有选中的样式(select),然后让当前选中的这个li和对应的div有选中的样式 function changeTab(nIndex) { for (var i = 0; i < oLis.length; i++) {  oLis[i].className = null;  oDivs[i].className = null; } oLis[nIndex].className = "select"; oDivs[nIndex].className = "select"; } 1、传统的循环绑定事件的方式 for (var i = 0; i < oLis.length; i++) { oLis[i].onmouseover = function () { changeTab(i); }; }   > 这种方式不能实现我们的效果,为什么?   > 我们是循环所有的li,给每一个li都绑定了鼠标滑过的事件-> /* i=0 oLis[0].onmouseover=function(){changeTab(i);}; 我们绑定事件其实是把匿名函数定义的主体赋值给元素的事件行为 -> oLis[0].onmouseover=xxxfff000; i=1 oLis[1].onmouseover=function(){changeTab(i);}; ... i=4 oLis[4].onmouseover=function(){changeTab(i);}; i=5 循环结束 */ 当我们手动触发的这些行为的时候,比如触发第一个li的onmouseover,执行第一个绑定的方法:行程一个私有的作用域->形参赋值->预解释->代码执行,遇到了一个变量i,不是自己的私有的,找全局作用域下的i,这个i的值已经变为循环结束后的5,所以不是我们期望的索引值... 2、如何解决这个问题? **[作用域式解决]** 当触发onmouseover的时候,全局的i变为了5,我们找全局的肯定不行,但是我可一这样来操作: 在当前私有作用域和全局作用域之间在嵌入一层作用域A,然后让A中有一个私有的变量i,存储的是自己的索引即可 for (var i = 0; i < oLis.length; i++) { (function (i) { oLis[i].onmouseover = function () { changeTab(i); }; })(i);//每一次循环把当前i的值(0,1,2,3,4)赋值给形参i } 函数执行形成不销毁的私有的作用域的第二种情况: 在一个函数中,给函数外面的DOM元素绑定事件 -> 由于给事件绑定的方法是一个引用数据类型值,而元素不属于这个作用域,而是函数外面的变量,这样也相当于外面的东西占用了函数里面的内存,当前的私有作用域不销毁 for (var i = 0; i < oLis.length; i++) { oLis[i].onmouseover = function (i) { return function () { changeTab(i); }; }(i); } 弊端:会形成多个不销毁的私有的作用域,占内存 **[自定义属性的方式]** 自定义属性处理问题是JS中最常用的编程思想 for (var i = 0; i < oLis.length; i++) { oLis[i].index = i;//每一次循环把当前li的索引存储到自己的自定义属性index上,后期需要用到索引的时候我们只需要把自定义属性index的值获取到拿来用即可 oLis[i].onmouseover = function () { //this->当前鼠标滑过的这个li changeTab(this.index); }; } **案例2:用setTimeout实现把p相对上一个p向右移动100px;1秒中只实现一个P的移动;** setTimeout本身是同步的代码,但是setTimeout里面的函数是异步的代码;setTimeout告诉浏览器隔多少秒执行里面的函数;这个函数是脱离执行顺序的;属于异步代码; 代码如下: var oDiv = document.getElementById("div1"); var oPs = oDiv.getElementsByTagName("p"); for (i = 0; i < oPs.length; i++) { (function(i){ setTimeout(function(){ oPs[i].style.left=100*i+"px"; },i*1000) })(i); } 因为定时器里面的函数是异步的,而setTimeout本身是同步的;所以i和里面的i不一致;用一个闭包把他们包起来;然后传i进去;或者直接包住setTimeout里面的函数; setTimeout((function(i){ return function(){oPs[i].style.left=100*i+"px";} })(i),i*1000);