초보자에게는 여전히 자바스크립트 클로저를 이해하기 어렵습니다. 이 글을 쓰는 목적은 가장 많이 사용되는 단어를 사용하여 자바스크립트 클로저의 진정한 모습을 보여주고 초보자가 더 쉽게 이해할 수 있도록 하는 것입니다.
1. 폐쇄란 무엇인가요?
"공식적인" 설명은 다음과 같습니다. 클로저는 많은 변수와 이러한 변수에 바인딩된 환경을 포함하는 표현식(일반적으로 함수)이므로 이러한 변수도 표현식의 일부입니다. 나는 그의 설명이 너무 학문적이기 때문에 이 문장을 직접적으로 이해할 수 있는 사람은 거의 없다고 생각합니다.
사실 일반인의 관점에서 이 문장은 다음을 의미합니다. JavaScript의 모든 함수는 클로저입니다. 그러나 일반적으로 말하면, 중첩된 함수에 의해 생성된 클로저가 더 강력하며, 우리는 이를 대부분 "클로저"라고 부릅니다. 다음 코드를 보세요:
function a( ) {
var i = 0;
function b() {
alert( i);
}
return b;
}
var c = a();
c()
이 코드에는 두 가지 특징이 있습니다.
1. 함수 b는 함수 a 안에 중첩되어 있습니다.
2. 함수 a는 함수 b를 반환합니다.
이런 식으로 var c=a()를 실행하면 변수 c는 실제로 b 함수를 가리킵니다. 변수 i는 b에서 사용됩니다. c()를 실행하면 i 값을 표시하는 창이 나타납니다(첫 번째). 시간은 1)입니다. 이 코드는 실제로 클로저를 생성합니다. 이유는 무엇입니까? 함수 a 외부의 변수 c는 함수 a 내부의 함수 b를 참조하기 때문에, 즉
함수 a의 내부 함수 b가 함수 a 외부의 변수에 의해 참조되면 소위 "클로저" Bag이 생성됩니다. ".좀 더 명확하게 말해 보겠습니다. 소위 "클로저"는 생성자 본문에 다른 함수를 대상 개체의 메서드 함수로 정의하고, 이 개체의 메서드 함수는 차례로 외부 외부 함수 본문에 있는 임시 변수를 참조하는 것입니다.
이를 통해 대상 개체가 수명 동안 항상 메서드를 유지할 수 있는 한 원래 생성자 본문에서 사용된 임시 변수 값을 간접적으로 유지할 수 있습니다. 초기 생성자 호출이 종료되고 임시변수의 이름은 사라졌지만, 변수의 값은 항상 대상 객체의 메소드에서 참조할 수 있으며, 이 메소드를 통해서만 값에 접근할 수 있다.
동일한 생성자가 다시 호출되더라도 새로운 객체와 메소드만 생성됩니다. 새 임시 변수는 새 값에만 해당하며 마지막 호출과 독립적입니다. 클로저에 대해 더 깊이 이해하기 위해 클로저의 기능과 효과를 계속해서 살펴보겠습니다.
2. 폐쇄의 기능과 효과는 무엇인가요? 요컨대 클로저의 기능은 a가 실행되고 반환된 후 a의 내부 함수 b의 실행으로 인해 a가 점유한 리소스를 회수하는 Javascript의 가비지 수집 메커니즘 GC를 방지하는 것입니다. a의 변수에 의존합니다. 이는 클로저의 역할에 대한 매우 간단한 설명입니다. 전문적이거나 엄격하지는 않지만 일반적인 의미는 클로저를 이해하는 데에는 단계별 프로세스가 필요하다는 것입니다.
위의 예에서 클로저의 존재로 인해 a의 i는 함수 a가 반환된 후에 항상 존재하게 됩니다. 이런 식으로 c()가 실행될 때마다 i는 추가 후 경고되는 i 값이 됩니다. 1. 그럼 다른 상황을 상상해 봅시다. a가 함수 b가 아닌 다른 것을 반환한다면 상황은 완전히 다릅니다.
a가 실행된 후 b는 a의 외부 세계로 반환되지 않고 a에서만 참조되기 때문입니다. 따라서 a와 b는 서로를 참조하지만 외부 세계(외부 참조)의 영향을 받지 않으며 함수 a와 b는 GC에 의해 재활용됩니다. (Javascript의 가비지 수집 메커니즘은 나중에 자세히 소개합니다.)
3. 클로저의 미시 세계 클로저와 함수 a와 관계에 대해 더 깊이 알고 싶다면 중첩 함수 b, 함수 실행 컨텍스트(실행 컨텍스트), 활성 객체(호출 객체), 범위(scope) 및 범위 체인(scope chain) 등 몇 가지 다른 개념을 도입해야 합니다. 이러한 개념을 설명하기 위해 정의부터 실행까지 함수 a의 프로세스를 예로 들어 보겠습니다.
1. 함수 a를 정의할 때 js 인터프리터는 a를 정의할 때 a가 있는 "환경"으로 함수 a의 범위 체인을 설정합니다. a가 전역 함수인 경우 범위 체인은 창 개체만 있습니다.
2. 함수 a를 실행하면 a는 해당 실행 컨텍스트로 들어갑니다.
3. 실행 환경을 생성하는 과정에서 먼저 a, 즉 a의 범위에 범위 속성이 추가되며 해당 값은 1단계의 범위 체인입니다. 즉, a.scope=a의 범위 체인입니다.
4. 그러면 실행 환경이 호출 개체를 생성합니다. 활성 개체도 속성은 있지만 프로토타입이 없고 JavaScript 코드에서 직접 액세스할 수 없는 개체입니다. 활성 개체를 만든 후 범위 체인의 맨 위에 활성 개체를 추가합니다. 이때 a의 범위 체인에는 a의 활성 개체와 창 개체라는 두 개체가 포함됩니다.
5. 다음 단계는 함수 a를 호출할 때 전달된 매개변수를 저장하는 활성 객체에 인수 속성을 추가하는 것입니다.
6. 마지막으로 함수 a의 모든 형식 매개변수와 내부 함수 b에 대한 참조를 a의 활성 개체에 추가합니다. 이번 단계에서는 함수 b의 정의가 완료되므로 3단계와 마찬가지로 함수 b의 스코프 체인은 b가 정의된 환경, 즉 a의 스코프에 설정된다.
이제 전체 함수 a의 정의부터 실행까지의 단계가 완료됩니다. 이때 a는 함수 b의 참조를 c에 반환하고 함수 b의 범위 체인에는 함수 a의 활성 개체에 대한 참조가 포함되어 있습니다. 이는 b가 a에 정의된 모든 변수와 함수에 액세스할 수 있음을 의미합니다. 함수 b는 c에 의해 참조되고 함수 b는 함수 a에 의존하므로 함수 a는 반환 후 GC에 의해 재활용되지 않습니다.
b 함수가 실행되면 위의 단계와 동일합니다. 따라서 실행 중 b의 범위 체인에는 b의 활성 개체, a의 활성 개체 및 창 개체의 3개 개체가 포함됩니다. 함수 b의 변수에 액세스할 때 검색 순서는 다음과 같습니다.
1. 존재하지 않으면 함수 a의 활성 객체를 찾을 때까지 계속 검색합니다.
2. 함수 b에 프로토타입 프로토타입 객체가 있는 경우 먼저 자신의 활성 객체를 검색한 후 자신의 프로토타입 객체를 검색한 다음 계속 검색합니다. 이것은 Javascript의 변수 조회 메커니즘입니다.
3. 전체 범위 체인에서 찾을 수 없으면 정의되지 않은 값이 반환됩니다.
요약하면 이 단락에서는 함수의 정의와 실행이라는 두 가지 중요한 단어가 언급됩니다. 이 기사에서는 함수의 범위는 함수가 실행될 때가 아니라 함수가 정의될 때 결정된다고 언급합니다(1단계와 3단계 참조). 이 문제를 설명하려면 코드를 사용하십시오.
function f(x ) {
var g = function () { return x; }
return g;
}
var h = f(1)>alert(h() );
이 코드의 변수 h는 f(g에서 반환됨)의 익명 함수를 가리킵니다.
◆ 함수 h의 범위가 경보(h())를 실행하여 결정된다고 가정하면, 이때 h의 범위 체인은 h의 활성 개체 -> 경고의 활성 개체 -> 창 개체입니다.
◆ 함수 h의 범위는 정의할 때 결정된다고 가정합니다. 즉, h가 가리키는 익명 함수는 정의할 때 범위가 결정됩니다. 그런 다음 실행 중에 h의 범위 체인은 h의 활성 개체 -> f의 활성 개체 -> 창 개체입니다.
첫 번째 가정이 true이면 출력 값은 정의되지 않으며, 두 번째 가정이 true이면 출력 값은 1입니다. 실행 결과는 함수가 정의될 때 함수의 범위가 실제로 결정된다는 것을 나타내는 두 번째 가정이 정확하다는 것을 증명합니다.
4. 클로저 적용 시나리오
1. 함수 내 변수를 보호합니다. 초기 예를 들어, 함수 a의 i는 함수 b를 통해서만 접근할 수 있고 다른 수단으로는 접근할 수 없으므로 i의 보안이 보호됩니다.
2. 메모리에 변수를 유지합니다. 이전 예제와 마찬가지로 클로저로 인해 함수 a의 i는 항상 메모리에 존재하므로 c()가 실행될 때마다 i는 1씩 증가합니다.
3. 변수 보안을 보호하여 JS 개인 속성 및 개인 메서드(외부에서 액세스할 수 없음)를 구현합니다. 권장 자료: http://javascript.crockford.com/private.html 전용 속성 및 메서드는 생성자 외부에서 액세스할 수 없습니다.
function Constructor(...) {
var that = this;
var membername = value
function membername(...) {...}
}
위의 세 가지 사항은 클로저의 가장 기본적인 적용 시나리오이며, 많은 고전적인 사례가 여기에서 유래합니다.
5. Javascript의 가비지 수집 메커니즘 Javascript에서는 객체가 더 이상 참조되지 않으면 해당 객체는 GC에 의해 재활용됩니다. 두 객체가 서로를 참조하고 더 이상 제3자가 참조하지 않는 경우, 서로를 참조하는 두 객체도 재활용됩니다. 함수 a는 b에 의해 참조되고 b는 a 외부의 c에 의해 참조되기 때문에 함수 a는 실행 후 재활용되지 않습니다.
6. 결론 JavaScript 클로저를 이해하는 것이 고급 JS 프로그래머가 되는 유일한 방법입니다. 그 해석과 작동 메커니즘을 이해해야만 더 안전하고 우아한 코드를 작성할 수 있습니다.