클로저 (클로저)는 Javascript를 초보자부터 심화까지 익히는 데 있어 매우 중요한 문턱입니다. 이는 Javascript 언어의 어려움이자 많은 고급 응용 프로그램의 특징이기도 합니다. 모두 폐쇄에 달려 있습니다. 아래에 나의 공부노트를 적어보세요~
자바스크립트의 클로저(Closure)에 대한 심층설명
자바스크립트 심층 설명
자바스크립트의 프로토타입 체인과 상속에 대한 심층 소개
프론트 엔드 프로그래밍에서 클로저를 사용하는 경우는 의도적이든 무의식적이든, 직접적이든 간접적이든 매우 일반적입니다. 클로저는 데이터 전송을 보다 유연하게 만들 수 있습니다(예: 일부 클릭 이벤트 처리)
!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()이 반환됩니다. 이 익명 함수에서는 외부()의 로컬 변수 localVal에 액세스할 수 있습니다. .outer()가 호출된 후 func()가 다시 호출되면 external()의 로컬 변수 localVal에 계속 액세스할 수 있습니다.
일반적인 함수와는 다릅니다. 함수가 직접적인 어휘 범위 외부에서 호출되는 경우에도 여전히 비지역 변수에 액세스할 수 있습니다. – 위키피디아
클로저는 다른 함수의 내부 변수를 읽을 수 있는 함수입니다. – 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)를 호출하여 함수의 전용 변수에 간접적으로 액세스하지만, _userId는 내보내기._userId를 직접 호출하여 얻을 수 없습니다. 이것도 Node에서 자주 사용하는 기능이에요~
다음과 같은 경우에는, 3p를 더하면 값은 aaa, bbb, ccc입니다. 우리가 원하는 것은 aaa를 클릭하여 1을 출력하고, bbb를 클릭하여 2를 출력하고, ccc를 클릭하여 3을 출력하는 것입니다.
document.body.innerHTML = "<p id=p1>aaa</p>" + "<p id=p2>bbb</p><p id=p3>ccc</p>"; for (var i = 1; i < 4; i++) { document.getElementById('p' + i). addEventListener('click', function() { alert(i); // all are 4! }); }
결과 aaa, bbb, ccc 클릭하면 모두 알림(4)~~
문제는 초기화가 완료되었을 때 i 값이 이미 4라는 점입니다
원하는 것을 얻으려면 aaa를 클릭하여 1을 출력하고, bbb를 클릭하여 2를 출력하고, ccc를 클릭하여 3을 출력합니다. 각 루프에서 익명 함수로 래핑해야 합니다. 다음과 같이 즉시 실행됩니다. 이렇게 하면 클로저 환경의 i에서 매번 Alert(i)의 값을 가져오고 이 i는 각 루프의 할당 i에서 가져오고 1, 2, 3을 출력합니다.
document.body.innerHTML = "<p id=p1>aaa</p>" + "<p id=p2>bbb</p>" + "<p id=p3>ccc</p>"; for (var i = 1; i < 4; i++) { !function(i){ //②再用这个参数i,到getElementById()中引用 document.getElementById('p' + i). addEventListener('click', function() { alert(i); // 1,2,3 }); }(i); //①把遍历的1,2,3的值传到匿名函数里面 }
다음 두 코드의 결과를 이해할 수 있다면 클로저의 작동 메커니즘을 이해해야 합니다. (루안 선생님의 답변) 이 질문은 초 단위로 요약되어 있습니다~~
Code Fragment 1
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
Code Fragment 2
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
위는 JavaScript 클로저에 대한 자세한 설명입니다. (마감) 코드 사진과 텍스트가 자세히 소개되어 있으니 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!