서문 : 여전히 입문 기사입니다. JavaScript에는 객체, 프로토 타입 상속 및 클로저에는 몇 가지 매우 중요한 언어 기능이 있습니다. 그 중에서도 폐쇄는 전통적인 정적 언어 C/C ++를 사용하는 프로그래머를위한 새로운 언어 기능입니다. 이 기사는 예제로 시작하여 JavaScript 클로저의 언어 기능을 소개하고 일부 ECMAScript 언어 사양을 결합하여 독자가 클로저를보다 깊이 이해할 수 있도록합니다.
참고 :이 기사는 입문 기사이며 예제 자료는 인터넷에서 편집됩니다. 당신이 마스터라면, 당신은 기사에 대한 기술 제안과 의견을 제시 할 수 있습니다. 이 기사에서는 JavaScript에 대해 설명하며 언어를 비교하고 싶지 않습니다. 자바 스크립트가 자연스럽게 불편하다면 우회를하십시오.
폐쇄는 무엇입니까?
폐쇄 란 무엇입니까? 클로저는 폐쇄이며, 이는 정적 언어가 가지고 있지 않은 새로운 기능입니다. 그러나 폐쇄는 너무 복잡하여 이해할 수없는 것이 아닙니다. 요컨대, 클로저는 다음과 같습니다.
클로저는 함수의 로컬 변수 세트이지만 함수가 반환 된 후에도 이러한 로컬 변수가 계속 존재합니다.
클로저는 함수의 "스택"이며 함수가 반환 된 후에는 해제되지 않습니다. 또한 이러한 기능 스택은 스택에 할당되지 않고 힙에 할당된다는 것을 이해할 수 있습니다.
함수 내에서 다른 함수를 정의하면 폐쇄가 생성됩니다.
위의 두 번째 정의는 첫 번째 보충 설명으로 첫 번째 정의의 피험자 예측 객체를 추출합니다. 폐쇄는 '로컬 변수'함수 세트입니다. 함수가 반환 된 후이 로컬 변수에 액세스 할 수 있습니다. (이것은 공식적인 정의는 아니지만이 정의는 폐쇄에 대한 이해에 더 도움이되어야합니다)
로컬 변수로서 함수의 코드에 의해 액세스 할 수 있으며이 언어와 정적 언어 사이에는 차이가 없습니다. 클로저 간의 차이점은 함수가 실행 된 후 함수 외부의 코드로 로컬 변수에 여전히 액세스 할 수 있다는 것입니다. 즉, 함수는 폐쇄에 "참조"를 반환 하거나이 "참조"를 외부 변수에 할당하여 폐쇄의 로컬 변수에 외부 코드에 의해 액세스되도록해야합니다. 물론,이 참조를 포함하는 엔티티는 객체가되어야합니다. JavaScript에서 기본 유형을 제외한 나머지는 객체이기 때문입니다. 불행히도 ECMAScript는 폐쇄시 로컬 변수에 액세스 할 수있는 관련 구성원과 방법을 제공하지 않습니다. 그러나 ECMAScript에서 함수 객체에 정의 된 내부 함수는 외부 함수에 직접 액세스 할 수있는 로컬 변수입니다. 이 메커니즘을 통해 다음과 같은 방식으로 폐쇄에 대한 액세스를 완료 할 수 있습니다.
코드 사본은 다음과 같습니다.
함수 인사말 (이름) {
var text = 'hello' + 이름; // 로컬 변수
// 폐쇄가 생성 될 때마다 내부 함수 객체가 발신자에게 반환됩니다.
return function () {alert (텍스트); }
}
var sayshello = 인사말 ( "클로저");
sayshello () // 클로저를 통해 로컬 변수 텍스트에 액세스
위의 코드의 실행 결과는 인사말 함수가 실행 된 후 SayHello () 함수가 여전히 정의 된 로컬 변수 텍스트에 액세스 할 수 있기 때문에 Hello Closure입니다.
좋아, 이것은 전설적인 폐쇄의 효과입니다. 클로저에는 싱글 톤, 전력 생성기 및 폐쇄 사용과 비교할 수없는 기타 JavaScript 모드와 같은 많은 응용 시나리오와 모드가 있습니다.
ECMAScript 클로저 모델
ECMAScript는 어떻게 폐쇄를 구현합니까? 심층적 인 이해를 원한다면 연구를위한 ECMAScript 사양을 얻을 수 있습니다. 나는 여기서 간단한 설명 만 제공 할 것이며 콘텐츠는 인터넷에서도 나옵니다.
ECMAScript 스크립트의 기능이 실행될 때 각 기능 협회에는 실행 컨텍스트 시나리오 (실행 컨텍스트)가 있으며 여기에는 세 부분이 포함됩니다.
어휘성 환경
가변 환경
이 바인딩
이 바인딩의 세 번째 요점은 폐쇄와 관련이 없으며이 기사에서는 논의되지 않습니다. 기능 실행 프로세스를 구문 분석하기 위해 문법 환경에서 사용되는 가변 식별자. 우리는 문법 환경을 환경 레코드 (Enviroment Recode)와 외부 참조 (포인터)의 두 가지 중요한 구성 요소를 포함하는 물체로 생각할 수 있습니다. 환경 레코드에는 함수에 의해 내부적으로 선언 된 로컬 변수와 매개 변수가 포함되어 있으며 외부 참조는 외부 기능 개체의 컨텍스트 실행 시나리오를 가리키는 것을 포함합니다. 이 참조 값은 글로벌 컨텍스트 시나리오에서 무효입니다. 이러한 데이터 구조는 일원 링크 목록을 형성하며, 각 기준은 외부 컨텍스트 시나리오를 가리 킵니다.
예를 들어, 위의 예제의 폐쇄 모델은 다음과 같아야합니다. Sayhello 함수는 가장 낮은 수준이고, 상위 레벨은 기능 인사말이며, 가장 바깥 쪽 레벨은 글로벌 장면입니다. 아래 그림과 같이 : 따라서 Sayshello가 호출 될 때, Sayshello는 컨텍스트 장면을 통해 로컬 변수 텍스트의 값을 찾을 것이므로 "Hello Closure"변수 환경 (변수 환경)과 문법 환경은 기본적으로 동일합니다. 특정 차이점은 ECMAScript 사양 문서를 참조하십시오.
폐쇄의 샘플 열
이전 기사에서는 JavaScript Closure가 무엇이며 JavaScript에서 폐쇄가 구현되는 방법을 대략적으로 이해합니다. 아래는 몇 가지 예를 목표로하여 폐쇄를 더 깊이 이해하는 데 도움이됩니다. 아래에는 5 개의 예가 있으며, 예제는 Dummies (Mirror)의 JavaScript 폐쇄에서 나온 것입니다. 예 1 : 폐쇄의 로컬 변수는 사본이 아닌 참조입니다.
코드 사본은 다음과 같습니다.
함수 say667 () {
// 폐쇄 내에있는 로컬 변수
var num = 666;
var sayalert = function () {alert (num); }
Num ++;
반환 saysalert;
}
var sayalert = say667 ();
sayalert ()
따라서 실행 결과는 666 대신 667을 나타냅니다.
예 2 : 다중 함수는 동일한 함수 내에서 정의되므로 동일한 폐쇄를 바인딩합니다.
코드 사본은 다음과 같습니다.
함수 setupsomeglobals () {
// 폐쇄 내에있는 로컬 변수
var num = 666;
// 함수에 대한 일부 참조를 글로벌 변수로 저장합니다
galertNumber = function () {alert (num); }
gincreasenumber = function () {num ++; }
gsetnumber = function (x) {num = x; }
}
setupsomeglobals (); // 세 가지 글로벌 변수에 값을 할당합니다
galertnumber (); // 666
gincreaseNumber ();
galertnumber (); // 667
gsetnumber (12); //
galertnumber (); // 12
예 3 : 루프에 함수를 할당 할 때 이러한 함수는 동일한 폐쇄를 바인딩합니다.
코드 사본은 다음과 같습니다.
함수 buildList (목록) {
var result = [];
for (var i = 0; i <list.length; i ++) {
var item = 'item' + list [i];
result.push (function () {alert (item + '' + list [i])});
}
반환 결과;
}
function testList () {
var fnlist = buildList ([1,2,3]);
// 혼란을 방지하기 위해 j 만 사용 - i를 사용할 수 있습니다.
for (var j = 0; j <fnlist.length; j ++) {
fnlist [j] ();
}
}
TestList의 실행 결과는 Item3 Undefined Window가 세 번 튀어 나오는 것입니다.이 세 가지 함수는 동일한 폐쇄를 바인딩하고 항목의 값이 마지막으로 계산 된 결과이지만, 루프에서 뛰어 내리면 I 값은 4이므로 목록 [4]의 결과가 정의되지 않았습니다.
예 4 : 내부 기능 정의 후이 변수가 선언 되더라도 외부 함수의 모든 로컬 변수가 폐쇄 중입니다.
코드 사본은 다음과 같습니다.
함수 saysalice () {
var sayalert = function () {alert (alice); }
// 폐쇄 내에있는 로컬 변수
var alice = 'Hello Alice';
반환 saysalert;
}
var helloalice = sayalice ();
helloalice ();
실행 결과는 "Hello Alice"팝업이있는 창입니다. 함수가 말한 후 로컬 변수가 선언하더라도 로컬 변수에 여전히 액세스 할 수 있습니다.
예 5 : 함수가 호출 될 때마다 새 클로저 생성
코드 사본은 다음과 같습니다.
기능 newClosure (somenum, someref) {
// 폐쇄 내에있는 로컬 변수
var num = somenum;
var anarray = [1,2,3];
var ref = someref;
반환 함수 (x) {
num += x;
anarray.push (num);
경고 ( 'num :' + num +
'/nanarray' + anarray.tostring () +
'/nref.somevar' + ref.somevar);
}
}
Closure1 = newClosure (40, {somevar : 'Closure 1'});
Closure2 = newClosure (1000, {somevar : 'Closure 2'});
클로저 1 (5); // num : 45 Anarray [1,2,3,45] Ref : 'somevar closure1'
Closure2 (-10); // num : 990 Anarray [1,2,3,990] Ref : 'somevar closure2'
폐쇄의 적용
싱글 톤 싱글 피스 :
코드 사본은 다음과 같습니다.
var singleton = function () {
var privatevariable;
함수 privatefunction (x) {
... Privatevariable ...
}
반품 {
FirstMethod : function (a, b) {
... Privatevariable ...
},
SecondMethod : function (c) {
... privatefunction () ...
}
};
} ();
이 단일 조각은 폐쇄를 통해 달성됩니다. 개인 구성원 및 방법의 캡슐화는 폐쇄를 통해 완료됩니다. 익명 주 기능 객체를 반환합니다. 객체에는 두 가지 방법이 포함되어 있습니다. 방법 1은 개인 변수를 사용할 수 있으며 방법 2는 내부 개인 기능에 액세스 할 수 있습니다. 주목해야 할 것은 익명의 주요 기능이 끝나는 '()'입니다. 이것이 없으면 '()'가 없으면 단일 조각을 만들 수 없습니다. 익명 함수는 고유 한 객체 만 반환 할 수 있으며 다른 곳에서는 호출 할 수 없기 때문입니다. 이것은 단일 조각을 생성하기 위해 클로저를 사용하는 방법입니다.