【笔记】关于js的匿名函数问题, 还有闭包的问题, 做下笔记

xiaoxiao2021-02-28  93

写在前面

看到这样一段js代码, 是不明白的, 于是上网找相关资料, 这是匿名函数的一种写法

!function($){ ... code ... }(jquery) (function($){ ... code ... })(jquery)

这两段是等价的, 都是匿名函数


再看下面的代码, 首先我alert 括号里的表达式, 用意在于, 验证一下下面的abc function 和 上面这个匿名函数是不是等价的, 答案, 是true;

alert(abc.constructor == (function(a,b,c){alert(2);}).constructor) function abc(a,b,c) { alert(2); }

再分析下如下代码


匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。

// 1.首先创建一个全局变量 var oEvent = {}; // 2.定义匿名函数,我用取反的方法, 比较方便看起来 ! function() { // 然后定义一些方法,变量 var addEvent = function(dom, event, fun){ console.info("执行addEvent方法啊....") } // 或者这样写 function removeEvent() { console.info("执行removeEvent方法啊....") } oEvent.addEvent = addEvent; oEvent.removeEvent = removeEvent; }(); // 在这段代码中函数addEvent和removeEvent都是局部变量,但我们可以通过全局变量oEvent使用它,这就大大减少了全局变量的使用,增强了网页的安全性。 我们要想使用此段代 // oEvent.addEvent(); // 这就执行了addEvent方法 oEvent.addEvent(document.getElementById('box') , 'click' , function(){}); // 这样更复杂点的

下面说说闭包的问题

闭包是什么?闭包是指某种程序语言中的代码块允许一级函数存在并且在一级函数中所定义的自由变量能不被释放,直到一级函数被释放前,一级函数外也能应用这些未释放的自由变量。   怎样?看得一头冒汗吧……没事,我也是(虽然是我是了解的,只是表达能力的问题)。让我们换个更加简单的方法说明:闭包,其实是一种语言特性,它是指的是程序设计语言中,允许将函数看作对象,然后能像在对象中的操作搬在函数中定义实例(局部)变量,而这些变量能在函数中保存到函数的实例对象销毁为止,其它代码块能通过某种方式获取这些实例(局部)变量的值并进行应用扩展。   不知道这么再解释后会否更加清晰,如果还是不明白,那么我们再简化一下:闭包,其实就是指程序语言中能让代码调用已运行的函数中所定义的局部变量。

var abc = function(y){ var x=y;// 这个是局部变量 return function(){ // 就是这里调用了闭包特性中的一级函数局部变量的x,并对它进行操作 alert(y--); alert(x++); alert(y--) ;// 引用的参数变量也是自由变量;} } }(5); abc(10); // 经测试,这个10参数对y根本没有用, 因为初始化5了, 这里改变不了 abc(); abc(); abc(); abc(x);

用闭包来优化代码

// 需求: 想两秒执行一次两个变量相加, 普通写法 function addForTime(x , y) { alert(x + y); } function delay(x, y, time) { setTimeout(addForTime(x , y) , time); // 首先这么写, 错误, 错误在哪? // 我实验, 他会立即执行alert(x+y), 然后也不会在3秒后在alert了. 我的理解它是直接将addForTime执行了, 而setTimeOut没有需要执行的function了 } function delay(x, y, time) { setTimeout('addForTime(' + x + ',' + y + ')', time); // 这么写效果是达到了, 但是看起来很难维护 } 红色字是最终的代码, 闭包的一种体现. function delay(x, y, time) { setTimeout(function () { addForTime(x, y); // 闭包就能解决,因为闭包特性 能用x, y 变量 }, time); } delay(1, 2, 3000);

最后, 注意下这个问题, 就是闭包引用父函数的变量, 但是如果这个变量是循环遍历的话, 那么匿名函数引用的是最终的值, 下面这个例子证明了这一点, 并且解决方法有多种, 这个我没亲自去实验, 但是我看懂了, 用的时候在来看看吧.

闭包允许内层函数引用父函数中的变量,但是该变量是最终值

/** * <body> * <ul> * <li>one</li> * <li>two</li> * <li>three</li> * <li>one</li> * </ul> */ var lists = document.getElementsByTagName('li'); for(var i = 0 , len = lists.length ; i < len ; i++){ lists[ i ].onmouseover = function(){ alert(i); }; }

你会发现当鼠标移过每一个<li>元素时,总是弹出4,而不是我们期待的元素下标。这是为什么呢?注意事项里已经讲了(最终值)。显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数( function(){ alert(i); })内部查找是否定义了 i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。 解决方法一:

var lists = document.getElementsByTagName('li'); for(var i = 0 , len = lists.length ; i < len ; i++){ (function(index){ lists[ index ].onmouseover = function(){ alert(index); }; })(i); }

解决方法二:

var lists = document.getElementsByTagName('li'); for(var i = 0, len = lists.length; i < len; i++){ lists[ i ].$$index = i; //通过在Dom元素上绑定$$index属性记录下标 lists[ i ].onmouseover = function(){ alert(this.$$index); }; }

解决方法三:

function eventListener(list, index){ list.onmouseover = function(){ alert(index); }; } var lists = document.getElementsByTagName('li'); for(var i = 0 , len = lists.length ; i < len ; i++){ eventListener(lists[ i ] , i); }
转载请注明原文地址: https://www.6miu.com/read-47427.html

最新回复(0)