1. 먼저 가변 스코프 체인을 알아야 합니다
변수 범위에는 전역 변수와 지역 변수라는 두 가지 유형이 있습니다. 함수에 정의되지 않은 변수는 전역 변수이고, 함수에 정의된 변수는 지역 변수입니다. 함수 내에서 변수를 정의할 때는 var 키워드를 사용해야 합니다.
JavaScript의 모든 코드에는 연관된 범위 체인이 있습니다. 이 범위 체인은 이 코드 조각의 "범위"에 있는 변수를 정의하는 개체 목록 또는 연결된 목록입니다. 최상위 코드의 범위는 전역 변수로 구성됩니다. 중첩 함수를 포함하지 않는 범위 체인에는 두 개의 개체가 있습니다. 하나는 정의된 함수 매개 변수와 지역 변수의 개체이고 다른 하나는 전역 변수 개체입니다. 중첩된 함수의 범위 체인에는 함수 매개변수와 지역 변수 - 외부 함수의 매개변수와 지역 변수 - 전역 변수라는 세 가지 개체가 있습니다. 함수는 범위 체인의 개체에 액세스할 수 있으므로 함수는 전역 변수에 액세스할 수 있지만 그 반대는 불가능합니다. 즉, 함수 내의 지역 변수는 함수 외부에서 액세스할 수 없습니다.
var a=1; function wai(){ alert(a); var m=10; n=20; } wai(); //=> 1; 函数内部可以访问全局变量 alert(m); //=> error; 外部访问函数局部变量报错 alert(n); //=> 20; 函数内部定义的变量未使用var关键字,所以是全局变量,外部可以访问
2. 지역 변수를 외부에서 읽는 방법
때때로 외부에서 함수 내의 지역 변수에 액세스해야 하는 경우가 있습니다. 자바스크립트 변수 범위의 특성을 이용하여 함수 내부에 하위 함수를 정의하고, 하위 함수는 상위 함수의 변수에 접근할 수 있습니다
function wai(){ var m=10; function nei(){ alert(m); } return nei; } var f = wai(); nei(); //=> error; nei()函数是一个局部变量,在外部不能访问 f(); //=> 10;
3. 폐쇄
이전 코드의 nei() 함수는 위에서 볼 수 있듯이 함수 내부에서 지역 변수를 읽을 수 있는 함수입니다. , 기능의 내부와 외부를 함께 연결하는 브릿지라고 볼 수 있다.
클로저에는 두 가지 기능이 있습니다:
먼저 앞서 언급했듯이 함수 내부에서 변수를 읽을 수 있습니다
둘째, 이러한 로컬 변수를 메모리에 저장하여 변수 데이터 공유를 실현할 수 있습니다
function wai(){ var m=99; function nei(){ alert(m); m++; } return nei; } var f= wai(); f(); //=> 99; f(); //=> 100; f(); //=> 101;
위의 예에서는 wai() 함수가 실행 중일 때 변수 m이 메모리에 저장됩니다. f()를 실행하면 m의 값을 읽을 수 있지만 직접 Alert(m)는 읽을 수 없습니다!
다음 예와 같이 익명 함수가 정의되고 클로저 함수가 익명 함수의 로컬 변수 i에 매개변수를 추가하고 Make가 매개변수를 전달할 수도 있습니다. 나는 증가한다
var wai=(function(){ var i=0; return function(num){ num+=i; alert(num); i++; } })(); wai(1);//1 wai(2);//3 wai(3);//5
클로저를 더 깊이 이해하기 위해 다음 예를 살펴보겠습니다.
이제 배열을 반환하는 함수를 정의하고 싶습니다. 배열의 각 요소는 함수이고 각 함수는 해당 인덱스 값을 팝업으로 표시합니다
이렇게 쓸 수도 있겠네요
function box(){ var arr=[]; for(i=0;i<5;i++){ arr[i]=function(){return i;} } return arr; } var a=box(); alert(a); //=>包含五个函数体的数组 alert(a[0]()); //=> 5; alert(a[1]()); //=> 5;
위 코드는 예상한 대로 모든 팝업이 0,1,2,3,4가 아닌 5임을 발견합니다. 이는 i도 메모리에 존재하는 로컬 변수이기 때문입니다. ]() 이때 i의 값은 이미 5이고, box() 함수가 실행되는 동안 i의 값은 계속해서 증가합니다.
해결책: 클로저 구현
function box(){ var arr=[]; for(var i=0;i<5;i++){ arr[i]=(function(num){ return function(){return num;} })(i); } return arr; } var arr=box(); for(var i=0;i<5;i++){ alert(arr[i]());//0,1,2,3,4 }
4. 클로저 사용 시 주의사항
1) 클로저를 사용하면 함수의 변수가 메모리에 저장되어 많은 메모리를 소모하게 되므로 클로저를 남용할 수 없습니다. 그렇지 않으면 웹 페이지에서 성능 문제가 발생하고 메모리 누수가 발생할 수 있습니다. 즉. 해결책은 함수를 종료하기 전에 사용되지 않는 모든 지역 변수를 삭제하는 것입니다.
2) 클로저는 상위 함수 외부의 상위 함수 내부 변수 값을 변경합니다. 따라서 부모 함수를 객체로, 클로저를 퍼블릭 메소드로, 내부 변수를 프라이빗 값으로 사용하는 경우 부모 함수의 변수 값을 임의로 변경하지 않도록 주의해야 합니다.
5. 폐쇄에 관한 몇 가지 질문은 다음과 같습니다.
다음 코드의 결과를 이해할 수 있다면 클로저의 작동 메커니즘을 이해해야 합니다.
JS 코드
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; //=>嵌套函数的this为全局变量或undefined,不会继承父函数的this }; } }; alert(object.getNameFunc()()); //The Window
위 출력이 "The window"인 이유는 중첩 함수의 this가 상위 함수 this를 상속하지 않고 해당 값이 전역 변수이거나 정의되지 않았기 때문입니다(ECMAScript5에서). 따라서 반환되는 것은 이름입니다. 전역 개체의 변수입니다. 객체의 name 속성을 반환하려는 경우 코드는 다음과 같습니다.
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var cur=this; return function(){ return cur.name; }; } }; alert(object.getNameFunc()()); //=》My Object
위 코드는 상위 함수 개체의 이것을 cur 변수에 할당하고 중첩 함수는 cur 변수를 통해 해당 속성에 액세스할 수 있습니다
---------------------------------- --- ---------------------------------- --- -----
자바스크립트 클로저 예시
function outerFun() { var a=0; function innerFun() { a++; alert(a); } } innerFun(); //=>error
위 코드는 innerFun()의 범위가 externalFun() 내부에 있으며, externalFun() 외부에서 호출하는 것은 잘못되었습니다.
은 다음과 같은 클로저로 변경됩니다.
JS 코드
function outerFun() { var a=0; function innerFun() { a++; alert(a); } return innerFun; //注意这里 } var obj=outerFun(); obj(); //结果为1 obj(); //结果为2 var obj2=outerFun(); obj2(); //结果为1 obj2(); //结果为2
什么是闭包:
当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.
--------------------------------------------------------------------------------------------------------
再来看一个例子
Js代码
function outerFun() { var a =0; alert(a); } var a=4; outerFun(); //=> 0 alert(a); //=> 4
结果是 0,4 . 因为在函数内部使用了var关键字 维护a的作用域在outFun()内部.
再看下面的代码:
Js代码
function outerFun() { //没有var a =0; alert(a); } var a=4; outerFun(); //=> 0 alert(a); //=> 0
结果为 0,0 真是奇怪,为什么呢?
作用域链是描述一种路径的术语,沿着该路径可以确定变量的值 .当执行a=0时,因为没有使用var关键字,因此赋值操作会沿着作用域链到var a=4; 并改变其值.