JS에서 클로저를 활용할 수 있는 일반적인 시나리오는 무엇입니까? (그림 및 텍스트 튜토리얼)

亚连
풀어 주다: 2018-05-18 16:18:24
원래의
1353명이 탐색했습니다.

시나리오 1: 함수 참조를 사용한 SetTimeout 호출

클로저의 일반적인 사용법은 특정 함수가 실행되기 전에 실행되는 함수에 대한 매개변수를 제공하는 것입니다. 예를 들어 웹 환경에서는 setTimeout 함수 호출의 첫 번째 매개변수로 함수를 사용하는 경우가 매우 흔합니다.

setTimeout은 실행될 함수(또는 자바스크립트 코드의 일부, 그러나 여기서 논의할 경우는 아님)를 첫 번째 매개변수로 취하고, 다음 매개변수는 실행을 지연하는 시간입니다. 코드 조각이 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);
로그인 후 복사

시나리오 2: 함수를 객체의 인스턴스 메서드에 연결

다음이 있습니다. 이러한 시나리오는 많습니다. 함수를 할당해야 합니다. 나중에 함수가 실행될 수 있도록 객체에 대한 참조를 할당해야 합니다. 그런 다음 클로저는 실행될 함수에 대한 참조를 제공하는 데 매우 도움이 될 수 있습니다. 실행될 때까지 함수에 액세스할 수 없기 때문입니다.

한 가지 예는 JavaScript 개체가 특정 DOM 요소와의 상호 작용에 참여하도록 캡슐화된다는 것입니다. doOnClick, doMouseOver 및 doMouseOut 메소드가 있습니다. 그리고 DOM 요소에서 해당 이벤트가 트리거될 때 이러한 메서드를 실행하려고 합니다. 그러나 DOM 요소와 관련하여 JavaScript 개체를 얼마든지 생성할 수 있으며 개별 인스턴스는 해당 개체를 인스턴스화하는 코드가 해당 개체로 어떤 작업을 수행할지 전혀 알 수 없습니다. 객체 인스턴스는 자신에게 참조가 할당될 전역 변수(있는 경우)를 모르기 때문에 자신을 "전역적으로" 참조하는 방법을 모릅니다.

그래서 문제는 특정 자바스크립트 객체 인스턴스와 관련된 이벤트 핸들러 함수를 실행하고 해당 객체의 어떤 메서드를 호출할지 아는 것입니다.

다음 예에서는 요소 이벤트 처리와 함께 객체 인스턴스의 관련 기능에 대한 간단한 클로저를 사용합니다. 이벤트 핸들러에는 이벤트 개체와 연결할 요소에 대한 참조를 전달하여 호출할 다양한 개체 인스턴스 메서드가 할당됩니다.

/* 
        一个给对象实例关联一个事件处理器的普通方法, 
        返回的内部函数被作为事件的处理器, 
        对象实例被作为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  
        }
로그인 후 복사

DhtmlObject의 모든 인스턴스는 이러한 요소가 전역 네임스페이스나 다른 DhtmlObjects 충돌로 인해 "오염"되는 다른 코드에 의해 처리되는 방식에 대해 걱정할 필요 없이 관심 있는 DOM 요소와 스스로를 연결할 수 있습니다.

시나리오 3: 관련 함수 세트 캡슐화

클로저는 관련 또는 종속 코드를 결합하는 데 사용할 수 있는 추가 범위를 생성할 수 있습니다. 이렇게 하면 코드 간섭의 위험을 최소화할 수 있습니다. 문자열을 생성하고 반복적인 연결 작업(예: 일련의 중간 문자열 생성)을 방지하는 데 함수가 사용된다고 가정해 보겠습니다. 한 가지 아이디어는 배열을 사용하여 문자열의 일부를 순차적으로 저장한 다음 Array.prototype.join 메서드를 사용하여 결과를 출력하는 것입니다(빈 문자열을 인수로 사용). 배열은 출력 버퍼 역할을 하지만 로컬로 정의하면 함수가 실행될 때마다 다시 생성됩니다. 이 배열이 모든 함수 호출의 유일한 변수로 할당된다면 이는 약간 과잉이 될 것입니다.

한 가지 해결책은 배열을 다시 만들지 않고도 다시 사용할 수 있도록 전역 변수로 승격하는 것입니다. 하지만 결과는 생각만큼 간단하지 않습니다. 또한 전역 변수가 버퍼 배열을 사용하는 함수와 연결되면 두 번째 전역 속성(함수 자체도 창 개체의 속성임)이 연결됩니다. 배열을 사용하면 코드의 특정 제어 가능성이 상실됩니다. 왜냐하면 다른 곳에 사용된다면 말이죠. 이 코드의 작성자는 포함된 함수의 정의와 배열 정의의 논리를 기억해야 했습니다. 또한 함수 이름이 전역 네임스페이스에서 고유한지 확인하는 대신 함수와 연결된 배열의 이름이 전역 네임스페이스에서 고유한지 확인해야 하므로 코드를 다른 코드와 통합하는 것이 덜 쉬워집니다. 글로벌 네임스페이스 .

클로저를 사용하면 버퍼 배열이 의존하는 함수를 연결(완전히 포함)할 수 있으며 동시에 버퍼 배열의 속성 이름이 마치 전역 공간에 할당된 것처럼 유지하면서 이름 충돌 위험을 피할 수 있습니다. 코드 상호 작용 간섭.

여기서 한 가지 비결은 인라인 함수 표현식을 실행하여 추가 실행 컨텍스트를 생성하고 해당 함수 표현식이 외부 코드에서 사용되는 인라인 함수를 반환하도록 하는 것입니다. 버퍼 배열은 인라인으로 실행되는 함수 표현식에서 지역 변수로 정의됩니다. 한 번만 호출되므로 배열은 한 번만 생성됩니다. 그러나 배열은 이에 의존하는 함수에 항상 액세스할 수 있으며 재사용할 수 있습니다.

다음 코드는 일부가 변경되지 않은 HTML 문자열을 반환하는 함수를 생성하지만 변경되지 않은 문자열은 매개변수로 전달된 변수와 함께 삽입되어야 합니다.

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

/* 
         定义一个全局变量: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;);  
            });  
        })();
로그인 후 복사

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

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

相关文章:

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

JS实现数组去重算法

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

위 내용은 JS에서 클로저를 활용할 수 있는 일반적인 시나리오는 무엇입니까? (그림 및 텍스트 튜토리얼)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿