간단히 말해서 자바 스크립트 클로저 로 기능 할 수 액세스를 가변 되는 어휘 - 부모 함수에서 선언을 .
더 자세한 설명을 보자. 클로저를 이해하려면 JavaScript의 변수 범위를 이해하는 것이 중요합니다.
범위
JavaScript 범위는 함수로 정의됩니다. 모든 함수는 새로운 범위를 정의합니다.
다음 예제를 고려하십시오.
function f()
{//begin of scope f
var foo='hello'; //foo is declared in scope f
for(var i=0;i<2;i++){//i is declared in scope f
//the for loop is not a function, therefore we are still in scope f
var bar = 'Am I accessible?';//bar is declared in scope f
console.log(foo);
}
console.log(i);
console.log(bar);
}//end of scope f
f 인쇄를 호출
hello
hello
2
Am I Accessible?
이제 g
다른 함수 내에 정의 된 함수가있는 경우를 고려해 봅시다 f
.
function f()
{//begin of scope f
function g()
{//being of scope g
/*...*/
}//end of scope g
/*...*/
}//end of scope f
f
의 어휘 부모 를 호출 합니다 g
. 앞에서 설명했듯이 이제 우리는 두 가지 범위를 갖습니다. 범위 f
와 범위g
.
그러나 한 범위는 다른 범위 내에 "내"있으며, 하위 함수의 범위는 부모 함수 범위의 일부입니까? 부모 함수의 범위에서 선언 된 변수는 어떻게됩니까? 하위 기능의 범위에서 액세스 할 수 있습니까? 바로 폐쇄가 시작되는 곳입니다.
폐쇄
JavaScript에서 함수 g
는 범위에 선언 된 변수 g
뿐만 아니라 상위 함수 범위에 선언 된 변수에도 액세스 할 수 있습니다.f
.
다음을 고려하십시오.
function f()//lexical parent function
{//begin of scope f
var foo='hello'; //foo declared in scope f
function g()
{//being of scope g
var bar='bla'; //bar declared in scope g
console.log(foo);
}//end of scope g
g();
console.log(bar);
}//end of scope f
f 인쇄를 호출
hello
undefined
라인을 보자 console.log(foo);
. 이 시점에서 우리는 범위 내에 있으며 scope 에 선언 된 g
변수에 액세스하려고합니다 . 그러나 앞에서 언급했듯이 여기서는 어휘 부모 함수에 선언 된 변수에 액세스 할 수 있습니다. 의 어휘 부모입니다 . 따라서 인쇄됩니다.
이제 라인을 보자 . 이 시점에서 우리는 범위 내에 있으며 scope 에 선언 된 변수에 액세스하려고합니다 . 현재 범위에서 선언되지 않았으며 함수 가의 부모가 아니므 로 정의되지 않았습니다.foo
f
g
f
hello
console.log(bar);
f
bar
g
bar
g
f
bar
실제로 우리는 어휘 "grand parent"함수의 범위에서 선언 된 변수에 액세스 할 수도 있습니다. 따라서 함수 h
내에 정의 된 함수가 있다면g
function f()
{//begin of scope f
function g()
{//being of scope g
function h()
{//being of scope h
/*...*/
}//end of scope h
/*...*/
}//end of scope g
/*...*/
}//end of scope f
다음 h
함수의 범위에 선언 된 모든 변수에 액세스 할 수있을 것 h
, g
등을 f
. 이것은 클로저 로 이루어집니다 . JavaScript 클로저 에서는 어휘 부모 함수, 어휘 그랜드 부모 함수, 어휘 그랜드 부모 함수 등에서 선언 된 모든 변수에 액세스 할 수 있습니다. 이는 범위 체인 으로 볼 수 있습니다 . scope of current function -> scope of lexical parent function -> scope of lexical grand parent function -> ...
어휘 부모가없는 마지막 부모 함수까지
윈도우 객체
실제로 체인은 마지막 부모 함수에서 멈추지 않습니다. 특별한 범위가 하나 더 있습니다. 전역 범위 . 함수에서 선언되지 않은 모든 변수는 전역 범위에서 선언 된 것으로 간주됩니다. 글로벌 스코프에는 두 가지 특성이 있습니다.
- 전역 범위에서 선언 된 모든 변수는 모든 곳에서 액세스 가능
- 전역 범위에서 선언 된 변수는
window
객체 의 속성에 해당 합니다.
따라서 foo
전역 범위에서 변수를 선언하는 두 가지 방법이 있습니다 . 함수에서 선언하지 않거나 foo
윈도우 객체 의 속성 을 설정하여 .
두 시도 모두 클로저를 사용합니다.
더 자세한 설명을 읽었으므로 이제 두 솔루션 모두 클로저를 사용하는 것이 분명 할 수 있습니다. 그러나 확실하게 증거를 만들어 봅시다.
새로운 프로그래밍 언어를 만들어 보자. JavaScript-No-Closure. 이름에서 알 수 있듯이 JavaScript-No-Closure는 클로저를 지원하지 않는다는 점을 제외하면 JavaScript와 동일합니다.
다시 말해;
var foo = 'hello';
function f(){console.log(foo)};
f();
//JavaScript-No-Closure prints undefined
//JavaSript prints hello
자, JavaScript-No-Closure를 사용하는 첫 번째 솔루션에서 어떤 일이 발생하는지 봅시다.
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}, 1000)
})();
}
따라서 이것은 인쇄됩니다 undefined
JavaScript-No-Closure에서 10 번 .
따라서 첫 번째 솔루션은 클로저를 사용합니다.
두 번째 해결책을 보자.
for(var i = 0; i < 10; i++) {
setTimeout((function(i2){
return function() {
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}
})(i), 1000);
}
따라서 이것은 인쇄됩니다 undefined
JavaScript-No-Closure에서 10 번 .
두 솔루션 모두 클로저를 사용합니다.
편집 :이 3 개의 코드 스 니펫이 전역 범위에 정의되어 있지 않은 것으로 가정합니다. 그렇지 않으면 변수 foo
와 객체가 객체에 i
바인딩 window
되므로 window
JavaScript와 JavaScript-No-Closure 의 객체를 통해 액세스 할 수 있습니다 .