JavaScript 클로저(Closure)에 대한 심층 설명

高洛峰
풀어 주다: 2016-10-15 17:45:14
원래의
881명이 탐색했습니다.

클로저 - 모든 곳에서

프론트 엔드 프로그래밍에서는 클로저를 사용하는 것이 매우 일반적입니다. 의도적이든 무의식적이든, 직접적이든 간접적이든 클로저를 사용하는 경우가 많습니다. 클로저는 데이터 전송을 보다 유연하게 만들 수 있습니다(예: 일부 클릭 이벤트 처리)

!function() {      
  var localData = "localData here";    
     document.addEventListener('click',    //处理点击事件时用到了外部局部变量,比如这里的localData       
        function(){              
           console.log(localData); 
    }); 
}();
로그인 후 복사

또 다른 예는 다음과 같습니다. (매우 친숙하지 않나요~~)

!function() {      
  var localData = "localData here";      
  var url = "http://www.baidu.com/";      
  $.ajax({ 
     url : url,          
     success : function() {              
        // do sth...              
        console.log(localData); 
        } 
    }); 
}();
로그인 후 복사

자 또 다른 예를 보세요~~이런 상황이 우리가 보통 클로저라고 부르는 상황입니다

function outer() {   
  var localVal = 30;    
  return function(){      
    return localVal;    
  } 
} 
var func = outer();  
func(); // 30
로그인 후 복사

이 예에서는 외부()가 호출되어 익명 함수 function()을 반환합니다. external()의 localVal에 접근할 수 있으며, external() 호출이 완료된 후 func()를 다시 호출하면 external()의 로컬 변수 localVal에 계속 접근할 수 있습니다

클로저의 개념

클로저는 일반 클로저와 다릅니다. 직접적인 어휘 범위 외부에서 호출될 때 함수가 지역 변수가 아닌 변수에 계속 액세스할 수 있도록 허용하는 함수입니다. --Wikipedia

클로저는 다른 함수의 내부 변수를 읽을 수 있는 함수입니다. --Ruan Yifeng

Javascript 언어에서는 함수 내부의 하위 함수만 지역 변수를 읽을 수 있으므로 클로저는 간단히 "함수 내부에 정의된 함수"로 이해하면 됩니다.

그래서 클로저란 본질적으로 함수 내부와 함수 외부를 연결하는 다리입니다.

클로저의 목적

이 부분은 이 블로그에서 재현했습니다. post

클로저는 다양한 곳에서 사용될 수 있습니다. 가장 큰 용도는 두 가지입니다. 하나는 앞서 언급한 것처럼 함수 내부의 변수를 읽는 것이고, 다른 하나는 이러한 변수의 값을 메모리에 유지하는 것입니다.

function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
로그인 후 복사

이 코드에서 결과는 실제로 클로저 f2 함수입니다. 두 번 실행했는데, 처음에는 값이 999였고, 두 번째에는 값이 1000이었습니다. 이는 함수 f1의 지역 변수 n이 항상 메모리에 저장되며 f1이 호출된 후에 자동으로 지워지지 않음을 증명합니다.

왜 이런 일이 일어나는 걸까요? 그 이유는 f1이 f2의 상위 함수이고 f2가 전역 변수에 할당되어 f2가 항상 메모리에 있고 f2의 존재가 f1에 따라 달라지므로 f1은 항상 메모리에 있고 삭제되지 않기 때문입니다. 호출이 완료된 후 가비지 수집 메커니즘(가비지 수집)에 의해 재활용됩니다.

이 코드에서 주목할 만한 또 다른 점은 "nAdd=function(){n+=1}" 행입니다. 우선 var 키워드는 nAdd 이전에 사용되지 않으므로 nAdd는 오히려 전역 변수입니다. 지역변수보다 둘째, nAdd의 값은 익명 함수이고 이 익명 함수 자체도 클로저이므로 nAdd는 함수 외부의 함수 내부 지역 변수에 대해 연산을 수행할 수 있는 setter와 동일합니다.

클로저 캡슐화

(function() {   
   var _userId = 23492;   
   var _typeId = 'item';    
   var export = {}; 
     
   function converter(userId) {          
     return +userId; 
   } 
    export.getUserId = function() {         
       return converter(_userId);     
   } 
   export.getTypeId = function() {          
      return _typeId; 
   }         
   window.export = export;   //通过此方式输出
}());
 
  export.getUserId(); // 23492 
  export.getTypeId();  // item 
  export._userId;    // undefined  
  export._typeId;    // undefined       
  export.converter; // undefined
로그인 후 복사

클로저의 특성을 사용하면 일부 복잡한 함수 논리를 캡슐화할 수 있습니다. 이 예에서는 간접 액세스를 위해 내보내기 메소드(getUserId, getTypeId)를 호출합니다. 함수의 개인 변수이지만, import._userId를 직접 호출하여 _userId를 얻을 수는 없습니다. 이것도 Node에서 흔히 사용되는 기능입니다~

흔히 저지르는 실수: 루프 폐쇄

다음의 경우 ​​​​aaa, bbb, ccc 값을 가진 3개의 div를 추가합니다. aaa를 클릭하면 1이 출력되고, bbb를 클릭하면 2가 출력되고, ccc를 클릭하면 3이 출력됩니다.

document.body.innerHTML = "<div id=div1>aaa</div>" + "<div id=div2>bbb</div><div id=div3>ccc</div>";  
for (var i = 1; i < 4; i++) {      
  document.getElementById(&#39;div&#39; + i).         
    addEventListener(&#39;click&#39;, function() {         
    alert(i); // all are 4! 
    });  
}
로그인 후 복사

JavaScript 클로저(Closure)에 대한 심층 설명

결과적으로 aaa, bbb 또는 ccc를 클릭하면 됩니다. 출력 경고(4)~~

문제는 초기화가 완료되었을 때 i의 값이 이미 4라는 것입니다

원하는 결과를 얻으려면 aaa를 클릭하여 1을 출력하고 bbb를 클릭하여 2를 출력하고 ccc를 클릭하여 3을 출력합니다. 클로저 기술을 사용하려면 각 루프 동안 즉시 실행되는 익명 함수로 래핑합니다. 이런 방식으로 클로저 환경의 i에서 경고(i)의 값을 가져옵니다. . 이것은 각 루프의 할당 i가 1, 2, 3을 출력할 수 있습니다

document.body.innerHTML = "<div id=div1>aaa</div>" + "<div id=div2>bbb</div>" + "<div id=div3>ccc</div>";  
for (var i = 1; i < 4; i++) {
  !function(i){ //②再用这个参数i,到getElementById()中引用     
    document.getElementById(&#39;div&#39; + i).       
      addEventListener(&#39;click&#39;, function() {         
      alert(i); // 1,2,3
     });  
  }(i);  //①把遍历的1,2,3的值传到匿名函数里面
}
로그인 후 복사

JavaScript 클로저(Closure)에 대한 심층 설명

생각하는 질문

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。(来自阮老师)这题目总结得真秒~~

代码片段一。

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    return function(){
      return this.name;
    };
  }
};
alert(object.getNameFunc()());
로그인 후 복사

代码片段二。

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    var that = this;
    return function(){
      return that.name;
    };
  }
};
alert(object.getNameFunc()());
로그인 후 복사


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