JS闭包可被利用的常见场景小结

场景一:采用函数引用方式的setTimeout调用

闭包的一个通常的用法是为一个在某一函数执行前先执行的函数提供参数。例如,在web环境中,一个函数作为setTimeout函数调用的第一个参数,是一种很常见的应用。

setTimeout将要执行的函数(或者一段JavaScript代码,但这不是我们要讨论的情况)作为它的第一个参数,下一个参数是需要延迟执行的时间。如果一段代码想通过setTimeout来调用,那么它需要传递一个函数对象的引用来作为第一个参数。延迟的毫秒数作为第二个参数,但这个函数对象的引用无法为将要被延迟执行的对象提供参数。
但是,可以调用另一个函数来返回一个内部函数的调用,将那个内部函数对象的引用传递给setTimeout函数。内部函数执行时需要的参数,在调用外部函数时传递给它。setTimeout在执行内部函数时无需传递参数,因为内部函数仍然能够访问外部函数调用时提供的参数:

function callLater(paramA, paramB, paramC) { /*使用函数表达式创建并放回一个匿名内部函数的引用*/ return (function () { /* 这个内部函数将被setTimeout函数执行; 并且当它被执行时, 它能够访问并操作外部函数传递过来的参数 */ paramA[paramB] = paramC; }); } /* 调用这个函数将在它的执行上下文中创建,并最终返回内部函数对象的引用 传递过来的参数,内部函数在最终被执行时,将使用外部函数的参数 返回的引用被赋予了一个变量 */ var funcRef = callLater(elStyle, "display", "none"); /*调用setTimeout函数,传递内部函数的引用作为第一个参数*/ hideMenu = setTimeout(funcRef, 500);

场景二:将函数关联到对象的实例方法

有很多这样的场景:需要分配一个函数对象的引用,以便在未来的某个时间执行该函数。那么闭包对于为这个将要执行的函数提供引用会非常有帮助。因为该函数可能直到执行时才能够被访问。

有一个例子就是,一个javascript对象被封装用来参与一个特定DOM元素的交互。它有doOnClick、doMouseOver以及doMouseOut方法。并且想在DOM元素上对应的事件被触发时执行这些方法。但是,可能会有关联着DOM元素的任意数量的javascript对象被创建,并且单个的实例并不知道那些实例化它们的代码将如何处理它们。对象实例不知道怎样去“全局”地引用它们自己,因为它们不知道哪个全局变量(如果存在)的引用将被分配给它们。

所以,问题是执行一个与特定javascript对象实例关联的事件处理函数,并且知道调用那个对象的哪个方法。
接下来的一个例子,在有元素事件处理的对象实例的关联函数上使用一个简单的闭包。通过传递event对象以及要关联元素的一个引用,为事件处理器分配不同的对象实例方法以供调用。

/* 一个给对象实例关联一个事件处理器的普通方法, 返回的内部函数被作为事件的处理器, 对象实例被作为obj参数,对象上将要被调用的方法名称被作为第二个参数 */ function associateObjWithEvent(obj, methodName) { /*返回的内部函数被用来作为一个DOM元素的事件处理器*/ return (function (e) { /* 事件对象在DOM标准的浏览器中将被转换为e参数, 如果没有传递参数给事件处理内部函数,将统一处理成IE的事件对象 */ e = e || window.event; /* 事件处理器调用obj对象上的以methodName字符串标识的方法 并传递两个对象:通用的事件对象,事件处理器被订阅的元素的引用 这里this参数能够使用,因为内部函数已经被执行作为事件处理器所在元素的一个方法 */ return obj[methodName](e, this); }); } /* 这个构造器函数,通过将元素的ID作为字符串参数传递进来, 来创建将自身关联到DOM元素上的对象, 对象实例想在对应的元素触发onclick、onmouseover、onmouseout事件时 对应的方法被调用。 */ function DhtmlObject(elementId) { /* 调用一个方法来获得一个DOM元素的引用 如果没有找到,则为null */ var el = getElementWith(elementId); /* 因为if语句块,el变量的值在内部进行了类型转换,变成了boolean类型 所以当它指向一个对象,结果就为true,如果为null则为false */ if (el) { /* 为了给元素指定一个事件处理函数,调用了associateObjWithEvent函数, 利用它自己(this关键字)作为被调用方法的对象,并且提供方法名称 */ el.onclick = associateObjWithEvent(this, "doOnClick"); el.onmouseover = associateObjWithEvent(this, "doOnMouseOver"); el.onmouseout = associateObjWithEvent(this, "doOnMouseOut"); } } DhtmlObject.prototype.doOnClick = function (event, element) { //doOnClick body } DhtmlObject.prototype.doMouseOver = function (event, element) { //doMouseOver body } DhtmlObject.prototype.doMouseOut = function (event, element) { //doMouseOut body }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwywzy.html