>웹 프론트엔드 >JS 튜토리얼 >프론트엔드 개발이 꼭 알아야 할 JS 클로저와 애플리케이션_javascript 기술

프론트엔드 개발이 꼭 알아야 할 JS 클로저와 애플리케이션_javascript 기술

WBOY
WBOY원래의
2016-05-16 18:23:46882검색

프론트엔드 개발이 꼭 알아야 할 JS 프로토타입과 상속이라는 글에서 클로저에 대한 글을 쓰겠다고 언급한 적이 있습니다. 게다가 최근에 클로저 애플리케이션 역량을 강화해야 한다는 걸 알게 되었기 때문에 이 글은 더 이상 미룰 수 없습니다. 더 길게. 이 기사에서는 함수 클로저에 대해 설명하며 객체 클로저(예: with 사용)는 포함하지 않습니다. 제가 말한 내용이 틀렸다고 생각하시면 언제든지 댓글과 조언 부탁드립니다.
1. 폐쇄 이론
먼저 다음 개념을 이해해야 합니다.

실행 환경
함수가 호출될 때마다(함수가 호출될 때) 실행됨) 시스템은 함수의 실행 환경인 함수에 대한 폐쇄형 로컬 실행 환경을 생성합니다. 함수는 로컬 변수, 함수 매개변수 읽기 및 쓰기, 내부 논리 실행 등 항상 자체 실행 환경에서 실행됩니다. 실행 환경을 만드는 과정에는 함수의 범위를 만드는 과정이 포함되며, 함수도 자체 범위에서 실행됩니다. 다른 관점에서 보면 각 함수 실행 환경에는 범위 체인이 있고 하위 함수의 범위 체인에는 상위 함수의 범위 체인이 포함됩니다. 범위 및 범위 체인은 아래를 참조하세요.

스코프, 스코프 체인, 호출 객체
함수 범위는 어휘 범위와 동적 범위로 구분됩니다.
어휘 범위는 함수가 정의될 ​​때의 범위, 즉 정적 범위입니다. 함수가 정의되면 어휘 범위가 결정됩니다. 어휘 범위는 함수 구조의 중첩 관계에 따라 함수의 범위를 설명합니다. 이때 함수의 범위 체인이 형성됩니다. 범위 체인은 이러한 범위를 중첩된 계층 관계로 연결하는 것입니다. 함수의 내부 [[scope]] 속성은 이 범위 체인을 가리킵니다.
동적 범위는 함수 호출이 실행될 때의 범위입니다. 함수가 호출되면 함수 내부의 [[scope]] 속성이 먼저 함수의 범위 체인을 가리킨 다음 호출 개체가 생성되고 호출 개체는 함수 매개 변수 및 지역 변수를 기록하는 데 사용됩니다. 함수를 도메인 체인의 최상위에 배치합니다. 이때, [[scope]]는 정의할 때 스코프 체인을 가질 뿐만 아니라, 호출할 때 호출 객체도 생성하게 됩니다. 즉, 실행 환경의 범위는 함수가 정의될 ​​때 결정된 범위 체인과 함수에 의해 방금 생성된 호출 개체를 더해 새로운 범위 체인을 형성하는 것과 같습니다. 따라서 이는 동적 범위이고 범위 체인도 이에 따라 변경됩니다. 여기서 범위를 보면 실제로는 객체 체인입니다. 이러한 객체는 함수가 호출될 때 생성되는 호출 객체이며, 그 위에 있는 호출 객체는 최상위 전역 객체입니다.
예를 들어 전역 환경의 함수 A에 함수 B가 중첩되어 있는 경우 함수 B의 범위 체인은 함수 B의 범위 -> 함수 A의 범위 -> 전역 창의 범위입니다. . 함수 B가 호출되면 식별자를 찾을 때 함수 B의 범위 -> 함수 A의 범위 -> 전역 창의 범위에 따라 검색됩니다. 실제로는 호출에 따라 검색됩니다. 함수 B의 객체 -> 함수 A -> 전역 객체의 호출 객체를 이 순서대로 검색합니다. 즉, 함수가 호출될 때 함수의 범위 체인은 실제로 호출 개체 체인입니다.

클로저
동적 실행 환경에서는 데이터가 실시간으로 변경됩니다. 이러한 비영속적 변수의 값을 유지하기 위해 이러한 동적 데이터를 저장하는 캐리어로 클로저를 사용합니다(읽기). 다음 이 문장을 적용해 보면 아주 잘 이해될 것입니다. 클로저의 정의: 소위 "클로저"는 많은 변수와 이러한 변수에 바인딩된 환경이 있는 표현식(일반적으로 함수)을 의미하므로 이러한 변수도 표현식의 일부입니다.
클로저는 함수 안에 중첩된 내부 함수이며, 내부 함수는 외부 함수에 선언된 모든 지역 변수, 매개변수 및 기타 내부 함수에 액세스할 수 있습니다. 내부 함수가 외부 함수 외부에서 호출되면 클로저가 생성됩니다. (실제로 모든 함수는 전역 범위의 내부 함수이고 전역 변수에 접근할 수 있으므로 창을 닫는 것입니다)
 예를 들어 다음 예는

코드 복사 코드는 다음과 같습니다.


가비지 수집 메커니즘: 객체가 더 이상 참조되지 않으면 객체가 재활용됩니다.
위에서 언급한 몇 가지 개념을 결합하면 var test=f(1)을 실행하면 f의 호출 객체가 생성됩니다. 여기서는 실행 후 외부 실행 환경이 종료되지만 내부 함수는 A 변수입니다. 외부 기능 외부의 테스트 참조 f. 외부 함수에 의해 생성된 호출 개체 obj에는 이 내부 함수를 가리키는 속성이 있고 이제 이 내부 함수가 참조되므로 호출 개체 obj는 계속 존재하며 해당 함수 매개 변수 x 및 가비지 수집기에 의해 재활용되지 않습니다. 지역 변수 a는 이 호출 개체에서 유지됩니다. 호출 객체에 직접 접근할 수는 없지만 호출 객체는 내부 함수 범위 체인의 일부가 되었고 내부 함수에 의해 접근 및 수정될 수 있으므로 test()가 실행될 때 x와 a에 올바르게 접근할 수 있습니다. 따라서 외부 함수가 실행되면 클로저가 생성되고, 참조되는 외부 함수의 변수는 계속 존재하게 됩니다.
2. 클로저 적용
적용 1:
이는 정렬 알고리즘을 시뮬레이션하기 위해 js를 사용하는 동안 발생한 문제입니다. 각 삽입 후에 정렬된 배열을 출력하고 싶습니다.
 setTimeout(function() { $("proc").innerHTML = arr "
"; }, i * 500) ;
arr 배열은 각 정렬의 상태 값을 유지하지 않기 때문에 각 출력이 최종 정렬된 배열임을 알 수 있습니다. 끊임없이 변화하는 배열 값을 저장하기 위해 외부에 함수 레이어를 래핑하여 클로저를 구현하고 클로저를 사용하여 이 동적 데이터를 저장합니다. 아래의 클로저를 구현하는 데에는 두 가지 방법이 사용됩니다. 하나는 매개변수를 사용하여 배열의 값을 저장하는 것이고, 다른 하나는 임시 변수를 사용하여 값을 저장하는 것입니다. 클로저를 통해 저장해야 하는 모든 비영속 변수는 임시 변수 또는 매개변수라는 두 가지 방법으로 구현할 수 있습니다.

[Ctrl A 모두 선택 참고: 외부 J를 도입해야 하는 경우 실행하려면 새로 고쳐야 합니다.
]

애플리케이션 2:
이것은 클릭 이벤트 팝업 루프 인덱스 값을 각
  • 노드에 바인딩하는 Wuyou(원본 게시물을 보려면 여기를 클릭하세요)의 예입니다. 원래는
    id.onclick = function(){ Alert(i); } id.onclick = function(){alert(i);}
    최종 팝업이 원하는 1이 아닌 4인 것을 발견했습니다. , 2, 3, 왜냐하면 루프가 완료된 후 i 값이 4가 되기 때문입니다. i의 값을 저장하기 위해 클로저도 사용합니다:

    [Ctrl A 모두 선택 참고:
    외부 J를 도입해야 하는 경우 실행하려면 새로 고쳐야 합니다.
    ]

    ( ps: var a = (function(){})(); var a =new function(){}과 동일한 효과를 가지며 둘 다 자체 실행 함수를 나타냅니다.)
    애플리케이션 3:
    다음 코드는 캐시 애플리케이션, catchNameArr. catch 값은 익명 함수의 호출 개체에 저장됩니다. 반환된 개체는 CachedBox 변수에 의해 참조되므로 익명 함수의 호출 개체는 재활용되지 않으므로 catch 값이 유지됩니다. CachedBox.getCatch("regionId");를 통해 작동할 수 있습니다. 지역 ID를 찾을 수 없으면 백그라운드에서 가져옵니다. catchNameArr은 주로 캐시가 너무 커지는 것을 방지하기 위한 것입니다. 코드 복사
    코드는 다음과 같습니다.



    同理,也可以用这种思想实现自增长的ID。  
    复制代码 代码如下:



    应用4:
      这个是无忧上月MM的例子(点击这里查看原帖),用闭包实现程序的暂停执行功能,还蛮创意的。

    [Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]

    把这个作用延伸下,我想到了用他来实现window.confirm。

    [Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]

    看了上面的这些应用,再回到前面的一句话:在动态执行环境中,数据实时地发生变化,为了保持这些非持久型变量的值,我们用闭包这种载体来存储这些动态数据。这就是闭包的作用。也就说遇到需要存储动态变化的数据或将被回收的数据时,我们可以通过外面再包裹一层函数形成闭包来解决。
      当然,闭包会导致很多外部函数的调用对象不能释放,滥用闭包会使得内存泄露,所以在频繁生成闭包的情景下我们要估计下他带来的副作用。
      毕了。希望能对大家有所帮助。
    者:JayChow
    出处:http://ljchow.cnblogs.com
  • 성명:
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.