Maison > interface Web > js tutoriel > Quels sont les scénarios courants dans lesquels les fermetures peuvent être exploitées dans JS ? (Tutoriel image et texte)

Quels sont les scénarios courants dans lesquels les fermetures peuvent être exploitées dans JS ? (Tutoriel image et texte)

亚连
Libérer: 2018-05-18 16:18:24
original
1360 Les gens l'ont consulté

Scénario 1 : Appel de setTimeout à l'aide de la référence de fonction

Une utilisation courante des fermetures consiste à fournir des paramètres pour une fonction qui est exécutée avant l'exécution d'une certaine fonction. Par exemple, dans un environnement Web, il est très courant qu'une fonction soit utilisée comme premier paramètre de l'appel de fonction setTimeout.

setTimeout prend la fonction à exécuter (ou un morceau de code javascript, mais ce n'est pas le cas dont nous allons discuter) comme premier paramètre, et le paramètre suivant est le temps de retardement de l'exécution. Si un morceau de code veut être appelé via setTimeout, il doit alors transmettre une référence à l'objet fonction comme premier paramètre. Le nombre de millisecondes à retarder comme deuxième paramètre, mais la référence à cet objet fonction ne peut pas fournir de paramètres pour l'objet qui sera retardé.

Cependant, il est possible d'appeler une autre fonction qui renvoie un appel à une fonction interne, en passant une référence à cet objet de fonction interne à la fonction setTimeout. Les paramètres requis lors de l'exécution de la fonction interne lui sont transmis lors de l'appel de la fonction externe. setTimeout n'a pas besoin de passer de paramètres lors de l'exécution de la fonction interne, car la fonction interne peut toujours accéder aux paramètres fournis lorsque la fonction externe est appelée :

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

Scénario 2 : Associer la fonction à la méthode d'instance de l'objet

Il existe de nombreux scénarios dans lesquels vous devez attribuer une référence à un objet fonction afin d'exécuter la fonction à un moment donné dans le futur. Les fermetures peuvent alors être très utiles pour fournir une référence à la fonction qui sera exécutée. Parce que la fonction peut ne pas être accessible jusqu'à son exécution.

Un exemple est un objet JavaScript encapsulé pour participer à l'interaction avec un élément DOM spécifique. Il possède les méthodes doOnClick, doMouseOver et doMouseOut. Et vous souhaitez exécuter ces méthodes lorsque l'événement correspondant sur l'élément DOM est déclenché. Cependant, un nombre illimité d'objets JavaScript peuvent être créés associés à des éléments DOM, et les instances individuelles n'ont aucune idée de ce que le code qui les instancie en fera. Les instances d'objet ne savent pas comment se référer à elles-mêmes "globalement" car elles ne savent pas quelle variable globale (le cas échéant) une référence leur sera attribuée.

Donc, le problème est d'exécuter une fonction de gestionnaire d'événements associée à une instance d'objet javascript spécifique et de savoir quelle méthode de cet objet appeler.

L'exemple suivant utilise une simple fermeture sur la fonction associée d'une instance d'objet avec la gestion des événements d'élément. Les gestionnaires d'événements se voient attribuer différentes méthodes d'instance d'objet à appeler en transmettant l'objet événement et une référence à l'élément à associer.

/* 
        一个给对象实例关联一个事件处理器的普通方法, 
        返回的内部函数被作为事件的处理器, 
        对象实例被作为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  
        }
Copier après la connexion

Toute instance de DhtmlObject peut s'associer aux éléments DOM qui l'intéressent, sans avoir à se soucier de la façon dont ces éléments seront traités par un autre code ou "pollués" par l'espace de noms global ou un conflit. avec d'autres instances de DhtmlObject.

Scénario 3 : Encapsuler des ensembles de fonctionnalités associés

Les fermetures peuvent créer des étendues supplémentaires, qui peuvent être utilisées pour combiner du code associé ou dépendant. De cette façon, les risques d’interférence du code peuvent être minimisés. Supposons qu'une fonction soit utilisée pour créer une chaîne et éviter les opérations de concaténation répétées (telles que la création d'une série de chaînes intermédiaires). Une idée consiste à utiliser un tableau pour stocker des parties de la chaîne de manière séquentielle, puis à utiliser la méthode Array.prototype.join pour afficher le résultat (en utilisant une chaîne vide comme argument). Le tableau jouera le rôle de tampon de sortie, mais le définir localement entraînera sa recréation à chaque exécution de la fonction. Ce serait un peu exagéré si ce tableau était simplement attribué comme seule variable à chaque appel de fonction.

Une solution consiste à promouvoir le tableau en variable globale afin qu'il puisse être réutilisé sans avoir à être recréé. Mais le résultat n'est pas aussi simple qu'on le pense. De plus, si une variable globale est associée à une fonction qui utilise un tableau tampon, il y aura un deuxième attribut global (la fonction elle-même est également un attribut de l'objet window) associé. avec le tableau, ce qui fera perdre au code une certaine contrôlabilité. Parce que s'il est utilisé ailleurs. Le créateur de ce code devait se souvenir de la définition de la fonction incluse ainsi que de la logique de définition du tableau. Cela rend également le code moins facile à intégrer à d'autres codes, car au lieu de simplement avoir besoin de déterminer si le nom de la fonction est unique dans l'espace de noms global, il devient nécessaire de déterminer si le nom du tableau associé à la fonction est unique dans l'espace de noms global. espace de noms global.

Une fermeture permet au tableau tampon d'associer (inclure proprement) les fonctions dont il dépend, tout en conservant les noms de propriétés du tableau tampon comme s'ils étaient alloués dans l'espace global, tout en évitant les conflits de noms et les interactions de code. ingérence.

Une astuce ici consiste à créer un contexte d'exécution supplémentaire en exécutant une expression de fonction en ligne et à ce que cette expression de fonction renvoie une fonction en ligne utilisée par du code externe. Le tableau tampon est défini comme une variable locale dans l'expression de fonction exécutée en ligne. Il n'est appelé qu'une seule fois, le tableau n'est donc créé qu'une seule fois. Mais le tableau est toujours accessible aux fonctions qui en dépendent, et peut être réutilisé.

Le code suivant crée une fonction qui renverra une chaîne HTML, dont une partie est inchangée, mais ces chaînes inchangées doivent être entrecoupées des variables passées en paramètres.

一个内联执行的函数表达式返回了内部函数对象的一个引用。并且分配了一个全局变量,让它可以被作为一个全局函数来调用。而缓冲数组作为一个局部变量被定义在外部函数表达式中。它没有被扩展到全局命名空间中,并且无论函数什么时候使用它都不需要被再次创建。

/* 
         定义一个全局变量:getImgInPositionedDivHtml 
         被赋予对外部函数表达式一次调用返回的一个内部函数表达式 
         内部函数返回了一个HTML字符串,代表一个绝对定位的DIV 
         包裹这一个IMG元素,而所有的变量值都被作为函数调用的参数 
*/  
        var getImgInPositionedDivHtml = (function () {  
            /* 
            buffAr 数组被定义在外部函数表达式中,作为一个局部变量 
            它只被创建一次。数组的唯一实例对内部函数是可见的, 
            所以它可以被用于每一次的内部函数执行 
            空字符串仅仅被用来作为一个占位符,它将被内部函数的参数代替 
            */  
            var buffAr = [  
                 &#39;<div id="&#39;,  
                &#39;&#39;,   //index 1, DIV ID attribute  
                &#39;" style="position:absolute;top:&#39;,  
                &#39;&#39;,   //index 3, DIV top position  
                &#39;px;left:&#39;,  
                &#39;&#39;,   //index 5, DIV left position  
                &#39;px;width:&#39;,  
                &#39;&#39;,   //index 7, DIV width  
                &#39;px;height:&#39;,  
                &#39;&#39;,   //index 9, DIV height  
                &#39;px;overflow:hidden;\"><img src=\"&#39;,  
                &#39;&#39;,   //index 11, IMG URL  
                &#39;\" width=\"&#39;,  
                &#39;&#39;,   //index 13, IMG width  
                &#39;\" height=\"&#39;,  
                &#39;&#39;,   //index 15, IMG height  
                &#39;\" alt=\"&#39;,  
                &#39;&#39;,   //index 17, IMG alt text  
                &#39;\"><\/div>&#39;  
            ];  
            /* 
            返回一个内部函数对象,他是函数表达式执行返回的结果 
            */  
            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(&#39;&#39;);  
            });  
        })();
Copier après la connexion

如果一个函数依赖另一个或几个函数,但那些其他的函数并不期望与任何其他的代码产生交互。那么这个简单的技巧(使用一个对外公开的函数来扩展那些函数)就可以被用来组织那些函数。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JS取得最小公倍数与最大公约数

JS实现数组去重算法

使用JS实现购物车功能步骤详解

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal