Heim > Artikel > Web-Frontend > Was sind die häufigsten Szenarien, in denen Schließungen in JS ausgenutzt werden können? (Bild- und Text-Tutorial)
Szenario 1: Aufruf von setTimeout mithilfe einer Funktionsreferenz
Eine häufige Verwendung von Abschlüssen besteht darin, Parameter für eine Funktion bereitzustellen, die ausgeführt wird, bevor eine bestimmte Funktion ausgeführt wird. In einer Webumgebung kommt es beispielsweise sehr häufig vor, dass eine Funktion als erster Parameter des setTimeout-Funktionsaufrufs verwendet wird.
setTimeout verwendet die auszuführende Funktion (oder einen Teil des Javascript-Codes, aber das ist nicht der Fall, den wir besprechen werden) als ersten Parameter, und der nächste Parameter ist die Zeit, um die Ausführung zu verzögern. Wenn ein Code über setTimeout aufgerufen werden soll, muss er als ersten Parameter eine Referenz auf das Funktionsobjekt übergeben. Die Anzahl der zu verzögernden Millisekunden als zweiter Parameter, aber diese Funktionsobjektreferenz kann keine Parameter für das Objekt bereitstellen, das verzögert werden soll.
Es ist jedoch möglich, eine andere Funktion aufzurufen, die einen Aufruf an eine innere Funktion zurückgibt und einen Verweis auf dieses innere Funktionsobjekt an die Funktion setTimeout übergibt. Die zur Ausführung der internen Funktion erforderlichen Parameter werden ihr beim Aufruf der externen Funktion übergeben. setTimeout muss beim Ausführen der internen Funktion keine Parameter übergeben, da die interne Funktion weiterhin auf die bereitgestellten Parameter zugreifen kann, wenn die externe Funktion aufgerufen wird:
function callLater(paramA, paramB, paramC) { /*使用函数表达式创建并放回一个匿名内部函数的引用*/ return (function () { /* 这个内部函数将被setTimeout函数执行; 并且当它被执行时, 它能够访问并操作外部函数传递过来的参数 */ paramA[paramB] = paramC; }); } /* 调用这个函数将在它的执行上下文中创建,并最终返回内部函数对象的引用 传递过来的参数,内部函数在最终被执行时,将使用外部函数的参数 返回的引用被赋予了一个变量 */ var funcRef = callLater(elStyle, "display", "none"); /*调用setTimeout函数,传递内部函数的引用作为第一个参数*/ hideMenu = setTimeout(funcRef, 500);
Szenario 2: Zuordnen von Funktionen zu Instanzmethoden von Objekten
Es gibt viele Szenarios: Sie müssen einem Funktionsobjekt einen Verweis zuweisen, um die Funktion zu einem späteren Zeitpunkt auszuführen. Dann können Abschlüsse sehr hilfreich sein, um einen Verweis auf die auszuführende Funktion bereitzustellen. Weil die Funktion möglicherweise erst nach der Ausführung zugänglich ist.
Ein Beispiel ist ein JavaScript-Objekt, das gekapselt ist, um an der Interaktion mit einem bestimmten DOM-Element teilzunehmen. Es verfügt über die Methoden doOnClick, doMouseOver und doMouseOut. Und möchten diese Methoden ausführen, wenn das entsprechende Ereignis für das DOM-Element ausgelöst wird. Es können jedoch beliebig viele JavaScript-Objekte erstellt werden, die mit DOM-Elementen verknüpft sind, und einzelne Instanzen haben keine Ahnung, was der Code, der sie instanziiert, mit ihnen machen wird. Objektinstanzen wissen nicht, wie sie „global“ auf sich selbst verweisen sollen, da sie nicht wissen, welcher globalen Variablen (falls vorhanden) ihnen eine Referenz zugewiesen wird.
Das Problem besteht also darin, eine Event-Handler-Funktion auszuführen, die einer bestimmten Javascript-Objektinstanz zugeordnet ist, und zu wissen, welche Methode dieses Objekts aufgerufen werden soll.
Das nächste Beispiel verwendet einen einfachen Abschluss für die zugehörige Funktion einer Objektinstanz mit Elementereignisbehandlung. Ereignishandlern werden verschiedene Objektinstanzmethoden zum Aufrufen zugewiesen, indem sie das Ereignisobjekt und einen Verweis auf das zu verknüpfende Element übergeben.
/* 一个给对象实例关联一个事件处理器的普通方法, 返回的内部函数被作为事件的处理器, 对象实例被作为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 }
Jede Instanz von DhtmlObject kann sich mit den DOM-Elementen verknüpfen, an denen sie interessiert ist, ohne sich Gedanken darüber machen zu müssen, wie diese Elemente von anderem Code verarbeitet werden, durch den globalen Namespace „verschmutzt“ werden oder mit dem globalen in Zusammenhang stehen Namespace. Andere Instanzen eines DhtmlObject-Konflikts.
Szenario 3: Kapselung verwandter Funktionssätze
Abschlüsse können zusätzliche Bereiche erstellen, die zum Kombinieren verwandten oder abhängigen Codes verwendet werden können. Auf diese Weise können die Gefahren von Codeinterferenzen minimiert werden. Angenommen, eine Funktion wird verwendet, um eine Zeichenfolge zu erstellen und wiederholte Verkettungsvorgänge (z. B. die Erstellung einer Reihe von Zwischenzeichenfolgen) zu vermeiden. Eine Idee besteht darin, ein Array zu verwenden, um Teile der Zeichenfolge nacheinander zu speichern, und dann die Methode Array.prototype.join zu verwenden, um das Ergebnis auszugeben (unter Verwendung einer leeren Zeichenfolge als Argument). Das Array übernimmt die Rolle des Ausgabepuffers, aber wenn es lokal definiert wird, wird es bei jeder Ausführung der Funktion erneut erstellt. Das wäre etwas übertrieben, wenn dieses Array jedem Funktionsaufruf einfach als einzige Variable zugewiesen würde.
Eine Lösung besteht darin, das Array in eine globale Variable hochzustufen, damit es wieder verwendet werden kann, ohne dass es erneut erstellt werden muss. Aber das Ergebnis ist nicht so einfach, wie Sie denken. Wenn eine globale Variable mit einer Funktion verknüpft ist, die ein Pufferarray verwendet, ist außerdem ein zweites globales Attribut (die Funktion selbst ist auch ein Attribut des Fensterobjekts) zugeordnet mit dem Array, wodurch der Code eine gewisse Steuerbarkeit verliert. Denn wenn es woanders verwendet wird. Der Ersteller dieses Codes musste sich die Definition der enthaltenen Funktion sowie die Logik der Array-Definition merken. Dadurch lässt sich der Code auch weniger einfach in anderen Code integrieren, da nicht nur ermittelt werden muss, ob der Funktionsname im globalen Namespace eindeutig ist, sondern auch ermittelt werden muss, ob der Name des mit der Funktion verknüpften Arrays im globalen Namespace eindeutig ist globaler Namensraum.
Eine Schließung ermöglicht es dem Pufferarray, die Funktionen, von denen es abhängt, zuzuordnen (sauber einzuschließen), während die Eigenschaftsnamen des Pufferarrays so beibehalten werden, als ob sie im globalen Raum zugewiesen wären, und gleichzeitig Namenskonflikte und Codeinteraktionen vermieden werden Interferenz.
Ein Trick hier besteht darin, einen zusätzlichen Ausführungskontext zu erstellen, indem man einen Inline-Funktionsausdruck ausführt und diesen Funktionsausdruck eine Inline-Funktion zurückgeben lässt, die von externem Code verwendet wird. Das Pufferarray wird als lokale Variable im inline ausgeführten Funktionsausdruck definiert. Es wird nur einmal aufgerufen, daher wird das Array nur einmal erstellt. Das Array ist jedoch für Funktionen, die davon abhängen, immer zugänglich und kann wiederverwendet werden.
Der folgende Code erstellt eine Funktion, die eine HTML-Zeichenfolge zurückgibt, von der ein Teil unverändert bleibt, aber diese unveränderten Zeichenfolgen müssen mit den als Parameter übergebenen Variablen durchsetzt werden.
一个内联执行的函数表达式返回了内部函数对象的一个引用。并且分配了一个全局变量,让它可以被作为一个全局函数来调用。而缓冲数组作为一个局部变量被定义在外部函数表达式中。它没有被扩展到全局命名空间中,并且无论函数什么时候使用它都不需要被再次创建。
/* 定义一个全局变量:getImgInPositionedDivHtml 被赋予对外部函数表达式一次调用返回的一个内部函数表达式 内部函数返回了一个HTML字符串,代表一个绝对定位的DIV 包裹这一个IMG元素,而所有的变量值都被作为函数调用的参数 */ var getImgInPositionedDivHtml = (function () { /* buffAr 数组被定义在外部函数表达式中,作为一个局部变量 它只被创建一次。数组的唯一实例对内部函数是可见的, 所以它可以被用于每一次的内部函数执行 空字符串仅仅被用来作为一个占位符,它将被内部函数的参数代替 */ var buffAr = [ '<div id="', '', //index 1, DIV ID attribute '" style="position:absolute;top:', '', //index 3, DIV top position 'px;left:', '', //index 5, DIV left position 'px;width:', '', //index 7, DIV width 'px;height:', '', //index 9, DIV height 'px;overflow:hidden;\"><img src=\"', '', //index 11, IMG URL '\" width=\"', '', //index 13, IMG width '\" height=\"', '', //index 15, IMG height '\" alt=\"', '', //index 17, IMG alt text '\"><\/div>' ]; /* 返回一个内部函数对象,他是函数表达式执行返回的结果 */ return (function (url, id, width, height, top, left, altText) { /* 分配各种参数给对应的数组元素 */ buffAr[1] = id; buffAr[3] = top; buffAr[5] = left; buffAr[13] = (buffAr[7] = width); buffAr[15] = (buffAr[9] = height); buffAr[11] = url; buffAr[17] = altText; /* 返回连接每个元素后创建的字符串 */ return buffAr.join(''); }); })();
如果一个函数依赖另一个或几个函数,但那些其他的函数并不期望与任何其他的代码产生交互。那么这个简单的技巧(使用一个对外公开的函数来扩展那些函数)就可以被用来组织那些函数。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
Das obige ist der detaillierte Inhalt vonWas sind die häufigsten Szenarien, in denen Schließungen in JS ausgenutzt werden können? (Bild- und Text-Tutorial). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!