>  기사  >  웹 프론트엔드  >  자바스크립트 클로저(Closure) 사용예제_자바스크립트 스킬에 대한 간략한 분석

자바스크립트 클로저(Closure) 사용예제_자바스크립트 스킬에 대한 간략한 분석

WBOY
WBOY원래의
2016-05-16 15:29:011106검색

본 글의 예시에서는 자바스크립트 클로저(Closure) 사용법을 설명하고 있습니다. 참고하실 수 있도록 모든 사람과 공유하세요. 자세한 내용은 다음과 같습니다.

폐쇄는 '폐쇄'로 번역되는데, 이건 너무 학문적으로 포장된 것 같은 느낌이 듭니다. 책과 온라인 자료를 참고하여 간략히 살펴보겠습니다. (부적절하게 이해한 부분은 주의해 주시기 바랍니다.)

1. 폐쇄란 무엇인가

공식 답변: 소위 "클로저"는 많은 변수와 이러한 변수에 바인딩된 환경이 있는 표현식(일반적으로 함수)을 의미하므로 이러한 변수도 표현식의 일부입니다.

위의 정의를 읽고 나면 전문가가 아닌 경우 저처럼 화를 내며 이렇게 물을 것이라고 굳게 믿습니다. 이것이 tmd 인간의 언어인가요?
클로저를 이해하려면 코드가 가장 설득력이 있습니다.

function funcTest()
{
 var tmpNum=100; //私有变量
 //在函数funcTest内定义另外的函数作为funcTest的方法函数
 function innerFuncTest(
 {
    alert(tmpNum); //引用外层函数funcTest的临时变量tmpNum
 }
 return innerFuncTest; //返回内部函数
}
//调用函数
var myFuncTest=funcTest(); 
myFuncTest();//弹出100

위 코드에서는 댓글이 명확하게 작성되었습니다. 이제 우리는 "클로저"를 다음과 같이 이해할 수 있습니다. 함수 본문의 다른 함수를 대상 개체의 메서드 함수로 정의하고(예제에서는 함수 funcTest 내에서 funcTest의 메서드 함수로 다른 함수 innerFuncTest를 정의합니다), 메서드 함수 이 개체의 반대입니다. 외부 함수 본문에서 임시 변수를 참조하십시오(클로저는 변수 값을 간접적으로 유지하는 메커니즘입니다. 예제에서 내부 함수 innerFuncTest는 외부 함수 funcTest의 임시 변수 tmpNum을 참조합니다. 여기서는 임시 변수가 선언된 모든 지역 변수, 매개변수 및 기타 선언된 내부 함수에 포함될 수 있다는 점에 유의해야 합니다. 이러한 내부 함수 중 하나가 이를 포함하는 외부 함수 외부에서 호출되면 클로저가 형성됩니다(예제에서 함수를 호출할 때 myFuncTest는 실제로 innerFuncTest 함수를 호출합니다. 이는 funcTest의 내부 함수인 innerFuncTest가 외부에서 호출된다는 의미입니다) funcTest, 클로저가 생성됩니다).

2. 클로저 사용의 두 가지 예

여기 두 가지 예가 있습니다. 하나는 클로저가 문제를 일으키기 때문이고, 다른 하나는 클로저를 사용하여 함수 범위를 통해 매개변수를 교묘하게 바인딩하기 때문입니다.

이 두 가지 예와 관련된 HTML 마크업 조각은 다음과 같습니다.

<a href="#" id="closureTest0">利用闭包的例子(1秒后会看到提示)</a><br />
<a href="#" id="closureTest1">由于闭包导致问题的例子1</a><br />
<a href="#" id="closureTest2">由于闭包导致问题的例子2</a><br />
<a href="#" id="closureTest3">由于闭包导致问题的例子3</a><br />

(1) 폐쇄로 인한 문제

위의 HTML 태그 조각에는 4개의 3499910bf9dac5ae3c52d5ede7383485 요소가 있습니다. 이제 사용자가 클릭할 때 페이지에 순서가 보고되도록 마지막 3개에 이벤트 핸들러를 할당해야 합니다. 두 번째 링크에 연결하면 "첫 번째 링크를 클릭했습니다"라고 보고됩니다. 이를 위해 마지막 세 링크에 대한 이벤트 핸들러를 추가하는 다음 함수를 작성하면 됩니다.

function badClosureExample(){
  for (var i = 1; i <4; i++) {
    var element = document.getElementById('closureTest' + i);
    element .onclick = function(){
      alert('您单击的是第' + i + '个链接');
    }
  }
}

그런 다음 페이지가 로드된 후 이 함수를 호출하세요. 그렇지 않으면 오류가 보고될 수 있습니다.

window.onload = function(){
  badClosureExample();
}

실행 결과를 보면 마지막 세 개의 링크를 클릭하면 경고 상자에 어떤 정보가 표시되나요? ——모두 "네 번째 링크를 클릭했습니다"입니다. 당신을 놀라게 합니까? 왜?

분석: badClosureExample() 함수에서 element.onclick에 할당된 이벤트 핸들러, 즉 onclick 익명 함수는 badClosureExample() 함수가 완료된 후에(사용자가 링크를 클릭할 때) 호출되기 때문입니다. 호출할 때 변수 i를 평가해야 합니다. 파서는 먼저 이벤트 핸들러 내부를 검색하지만 i는 정의되지 않습니다. 그런 다음 badClosureExample() 함수에서 검색합니다. 이때 정의되지만 i의 값은 4입니다(for 루프는 i가 4보다 큰 경우에만 실행을 중지합니다). 따라서 해당 값을 얻습니다. 즉, 외부 함수(badClosureExample)의 범위에서 변수를 사용하는 경우 클로저(익명 함수)가 수행하는 작업과 정확히 같습니다. 게다가 이는 익명 함수 자체가 매개변수를 전달할 수 없기 때문에 발생합니다(따라서 자체 범위를 유지할 수 없음).

그렇다면 이 예에서 문제를 어떻게 해결해야 할까요? 실제로 방법은 많습니다(직접 작성해 보는 것이 나을 수도 있습니다). 코드가 비교적 간단하고 직접적이라고 생각합니다.

function popNum(oNum){
  return function(){
          alert('您单击的是第'+oNum+'个链接');
  }
}
function badClosureExample(){
  for (var i = 1; i <4; i++) {
    var element = document.getElementById('closureTest' + i);
    element .onclick =new popNum(i);
    }
}

(2) 클로저를 영리하게 사용하여 매개변수 바인딩

여전히 위의 HTML 조각을 사용하여 사용자가 첫 번째 링크를 클릭할 때 경고 상자 팝업을 지연시키려고 합니다. 어떻게 해야 할까요? 대답은 다음과 같이 지정된 밀리초 후에 함수를 호출하는 setTimeout() 함수를 사용하는 것입니다.

코드 복사 코드는 다음과 같습니다.
setTimeout(someFunc,1000);
하지만 문제는 someFunc 함수에 매개변수를 전달할 수 없다는 것입니다. 이 문제는 클로저를 사용하여 쉽게 해결할 수 있습니다.
function goodClosureExample(oMsg){
  return function(){
    alert(oMsg);
  };
}

goodClosureExample 함수는 익명 함수(클로저)를 반환하는 데 사용됩니다. 그리고 반환된 익명 함수에 다음과 같은 매개변수를 전달하여 매개변수를 바인딩하도록 할 수 있습니다.


코드 복사 코드는 다음과 같습니다.
var good = goodClosureExample('이 매개변수는 클로저를 통해 바인딩됩니다.') ;

而此时,就可以将绑定了参数的good函数传递给setTimeout()实现延时警告了:
复制代码 代码如下:
setTimeout(good,1000) //此时good中已经绑定了参数

最后,测试通过的完整代码:
window.onload = function(){
  var element = document.getElementById('closureTest0');
  if (element) {
    var good = goodClosureExample('这个参数是由闭包绑定的');
    element.onclick = function(){
      setTimeout(good, 1000); //延迟1秒弹出提示
    }
  }
}

3、javascript的垃圾回收原理

(1)、在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收;

(2)、如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。

在js中使用闭包,往往会给javascript的垃圾回收器制造难题。尤其是遇到对象间复杂的循环引用时,垃圾回收的判断逻辑非常复杂,搞不好就有内存泄漏的危险,所以,慎用闭包。ms貌似已经不建议使用闭包了。

希望本文所述对大家JavaScript程序设计有所帮助。

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.