클로저 주제를 다루기 위해 자바 스크립트에서 변수 범위가 작동하는 방법을 검토해야합니다. 의 기본적인 기능과 관련된 문제를보고 시작하자 :
이 기능은 다음 선언하고 변수
counter
에 값 0을 할당하고,
function uniqueInteger(){
var counter = 0;
return ++counter;
}
console.log(uniqueInteger()); // returns '1'
console.log(counter); // undefined
가 증가하는 값을 반환합니다. 보시다시피 함수가 실행되는 동안 변수 카운터는 함수 내에서 액세스 할 수 있습니다. 그러나 일단 함수가 반환되면 변수는 더 이상 정의되지 않습니다. 이는 uniqueInteger()
함수의 범위의 일부이기 때문입니다. counter
변수가 개인이라고 말할 수 있습니다. 함수 uniqueInteger()
만 액세스 할 수 있습니다.
하지만 변수의 값을 기억하여 다음에이 함수가 호출 될 때 counter
이 0이 아니라 1에서 시작하기를 바랍니다. 한 가지 방법은 변수 counter
을 함수 외부에 선언하는 것이지만 더 이상 개인용이 아니며 다른 함수가 카운터 변수를 변경할 수 있습니다.
이 문제를 해결하려면 함수의 작동 방식을 살펴 봐야합니다. 함수가 호출되면 (위에서 보았 듯이) 함수의 변수는 반환 된 후에 사라집니다.그러나 함수의 범위 내에서, 중첩 된 기능은 여전히 부모 함수의 "개인"변수에 액세스 할 수 있습니다 :
function uniqueInteger(){
var counter = 0;
// an example of nested function accessing the counter variable:
return (function() { return ++counter })();
}
console.log(uniqueInteger()); // returns '1'
console.log(counter); // undefined
* 괄호로 호출의 수는() 정의 함수의 수와 일치합니다 . 중첩 함수 자체 호출되고 외부 기능 따라서 동일한 기능과 같이 쓸 수있다 라인 console.log(uniqueInteger());
호출된다
function uniqueInteger(){
var counter = 0;
// an example of nested function accessing the counter variable:
return function() { return ++counter };
}
console.log(uniqueInteger()()); // returns '1'
console.log(counter); // undefined
우리가 볼 수있는 바와 같이, 중첩 된 기능은 여전히 변수 카운터와 액세스 갖는다 uniqueInteger()
함수는 여전히 "1"을 반환합니다. uniqueInteger()
이 반환 된 후에 카운터 변수가 계속 사라지더라도 (나중에이 문제를 해결할 것입니다.) 중첩 된 함수가 counter
에 액세스한다는 사실은이 변수에 일을 수행 한 다음 결과를 반환 할 수있는 기능을 제공합니다. uniqueInteger()
이 호출 될 때마다 동일한 "범위 체인"이 존재하게됩니다. 매우 단순하게 말하면 이것을 어휘 범위이라고합니다.
이제 함수가 반환 된 후 변수 카운터가 사라지는 문제에 대해 살펴 보겠습니다. 여기서 일어나는 일은 가비지 콜렉션이라는 자바 스크립트 기능의 결과입니다. 함수와 변수가 더 이상 사용되지 않으면 "버려집니다". 그러나 함수의 반환 값에 대한 참조가있는 경우 (예를 들어 해당 함수가 외부 변수에 할당 된 경우), 우리가 말한 "범위 체인"에 따라 함수 내부의 변수와 함께 "기억"됩니다 위 :
function uniqueInteger(){
var counter = 0;
return function() { return ++counter };
}
var uniqueInt = uniqueInteger();
console.log(uniqueInt()); // returns '1'
console.log(uniqueInt()); // returns '2'
console.log(counter) // still "undefined"
그래서 어떻게 되었습니까? 중첩 된 함수의 반환 값을 외부 변수에 "저장"했기 때문에 변수 counter
은 가비지 수집을하지 않았고 다음에 uniqueInt()
이 호출되었을 때 counter는 여전히 1과 같습니다. 또한 상태가 저장되었다고 말할 수 있습니다 . 우리는 우리의 목표를 달성했습니다 : 우리는 변수를 변수로 정의하지 않고 호출간에 변수를 기억하고 비공개로 유지하는 함수를 만들었습니다.
우리는 위의 함수 정의의 표현으로이 기능을 다시 작성할 수 있습니다 :
var uniqueInteger = (function(){
var counter = 0;
return function() { return ++counter };
})();
console.log(uniqueInteger()); // returns '1'
console.log(uniqueInteger()); // returns '2'
console.log(counter) // still "undefined"
참고 두 가지 기능, 따라서이 해당 호출이 여전히 있다는 것을. 이번에는 함수 자체가 아니라 반환 값을 변수 uniqueInteger
에 저장하기 위해 외부 함수가 자체 호출됩니다. 그렇지 않으면 변수 uniqueInteger
의 반환 값은 function() { return ++counter; }
이됩니다. 위에서 설명한 기술은 본질적으로 클로저가 무엇입니까? 함수 내부에서 함수 (* 또는 객체)를 사용하여 호출간에 상태를 저장하면서 내부 값을 비공개로 유지하는 내부 값을 조작합니다.
var uniqueInteger = (function(){
var counter = 0;
return {
value: function() { return counter },
count: function() { return ++counter },
reset: function() { counter = 0; return counter;}
};
})();
console.log(uniqueInteger.value()); // 0
uniqueInteger.count();
console.log(uniqueInteger.value()); // 1
uniqueInteger.reset()
console.log(uniqueInteger.value()); // again 0
이 패턴은 당신이 자신의 개인 변수에 운영 자체에 포함 된 함수 객체를 가질 수 있습니다 :
또한 외부 함수의 값을 조작 기능을 가진 객체를 반환 할 수 있습니다 *
이름 충돌이나 외부로부터의 악의적 인 조작의 위험을 피하십시오.
나는 폐쇄를 너무 힘들어했지만 문학을 계속 읽으면 결국 결과가 나옵니다. 그냥 코드 주위에 놀고 계속 :
그래서 'x'를 통해 두 개의 폐쇄가 있지만 두 가지 방법은 변수를 공유하는 권리?과도한 폐쇄가 성능에 좋지 않다는 것을 읽었습니다. 폐쇄가 없으면 똑같이 할 수있는 방법이 있습니까? – vtortola