폐쇄란 무엇인가요? 클로저의 기능을 확인하세요. 다음 기사에서는 JavaScript의 클로저에 대해 설명합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.
프런트 엔드 학습 과정에서 필연적으로 많은 문제에 직면하게 되므로 오늘은 초보자의 관점에서 두 가지 질문에 대해 이야기하겠습니다.
클로저란 무엇입니까?
클로저의 기능은 무엇인가요?
사실 클로저는 자바스크립트를 배울 때 어디에나 있기 때문에 인식하고 받아들일 수만 있으면 됩니다. 클로저는 사용할 새로운 구문이나 패턴을 학습해야 하는 도구가 아닙니다. 클로저는 어휘 범위를 기반으로 코드를 작성하는 자연스러운 결과입니다. 코드를 작성할 때 의도적으로 클로저를 생성할 필요는 거의 없습니다.
이때 이미 많은 친구들이 속으로 중얼거리고 있을 거라 생각합니다. 어휘 범위는 무엇입니까? 당황하지 말고 천천히 들어보세요. 간단히 말해서 어휘 범위는 어휘 단계에서 정의되는 범위입니다. 즉, 어휘 범위는 코드를 작성할 때 변수와 블록 수준 범위를 배치하는 위치에 따라 결정되므로 어휘 분석기가 코드를 처리할 때(대부분의 경우) 범위는 변경되지 않습니다. ——"당신이 모르는 자바스크립트 볼륨"
먼저 예를 들어보겠습니다
function test(){ var arr = [] for(var i=0;i<10;i++){ arr[i]=function(){ console.log(i); } } return arr } var myArr = test() // myArr[0]() // myArr[1]() // ... for(var j = 0; j < 10; j++){ myArr[j]() } //为了避免繁琐此处使用了第二个循环来调用test函数里第一个循环里函数的打印出十个结果
이 코드를 먼저 분석해 보겠습니다. 이 코드가 실행되면 상식적으로 0부터 9까지 10개의 숫자가 순서대로 출력되어야 하지만 for 루프는 실행하는 데 시간이 걸리지 않습니다(마이크로초 단위로 무시할 수 있음). ] 안에는 10개의 function(){console.log(i);}가 있습니다. 이때 배열에 있는 함수는 for 루프의 실행 시간이므로 var myArr = test()가 테스트 함수를 호출하면 실행되지 않습니다. 무시하면 이때 i는 이미 10이므로 10개의 10이 출력됩니다.
이쯤 되면 누군가가 이것이 우리가 말하는 클로저와 무슨 상관이냐고 물을 것 같은데요. 그럼 이 코드를 약간 수정하여 누산기로 바꾸면 어떻게 구현할 수 있을까요?
그게 그렇게 간단하지 않다고 하는 거물들이 이때쯤 나올 거라 믿습니다?
첫 번째 for 루프가 블록 수준 범위가 되도록 정의를 허용하도록 var 정의를 변경한 다음 누산기가 될 수 있습니다. 물론 문제 없습니다.
하지만 오늘 우리가 이야기할 내용은 ES5에서 누산기를 구현하는 방법입니다. 그런 다음 다음 코드를 살펴보겠습니다.
function test(){ var arr = [] for(var i=0;i<10;i++){ (function(j){ arr[j]=function(){ console.log(j); } })(i) } return arr } var myArr = test() for(var j = 0; j < 10; j++){ myArr[j]() }
주의 깊은 친구들은 이것이 단지 루프의 함수 본문을 자체 실행 함수로 변경하는 것일 뿐이라는 것을 확실히 알 수 있을 것입니다. 그러나 이때 출력 결과는 다음과 같습니다. 0부터 9까지 10개의 숫자가 순차적으로 출력되며, 여기에는 클로저가 포함됩니다. 이 코드를 실행하기 시작하면 두 번째 for 루프가 각 자체 실행 함수가 실행될 때마다 자체 실행 함수가 생성됩니다. 실행 함수의 AO 객체. 자체 실행 함수의 AO 객체에는 j라는 속성이 있습니다. 평소와 같이 자체 실행 함수의 실행이 완료된 후에는 해당 AO 객체가 소멸되어야 합니다. [j] ( )가 실행되면 스코프 체인 상단에 있는 arr[j]의 AO 객체에서 속성 이름 j를 검색하지만 찾을 수 없습니다. 그런 다음 스코프 체인을 아래로 검색하여 찾습니다. 자체 실행 함수의 AO 객체이므로 자체 실행 함수가 실행 함수가 끝나면 해당 AO 객체는 가비지 수집 메커니즘에 의해 재활용되지 않습니다. 그렇지 않으면 myarr[j] ()가 다음과 같은 경우 오류가 보고됩니다. 실행되고 이때 클로저가 형성됩니다.
다른 예를 들어보겠습니다
function a(){ function b(){ var bbb = 234 console.log(aaa); } var aaa = 123 return b // b出生在a里面,但是被保存出去了 } var glob = 100 var demo = a() demo()
먼저 이 코드를 분석하기 위해 사전 컴파일을 사용합니다. 먼저 전역 GO 개체를 찾은 후 정의합니다. 선언, 전역 변수 선언을 찾고 변수 선언을 GO의 속성 이름으로 사용하고 값이 정의되지 않았습니다. 전역 선언의 경우 함수 선언을 찾고 함수 이름을 GO 객체의 속성 이름으로 사용합니다. 함수 본문에 값을 할당합니다. 현재는 GO{ glob: undefine--->100: undefine a: fa(){} }; 그런 다음 함수 a에 대해 AO{ aaa: undefound--->123;b: fb(){} }를 생성하고 마지막으로 함수 a에서 함수 b를 사전 컴파일하여 AO{ b: undefed-- ->234}를 생성합니다. ;이때 스코프 체인의 순서는 1. 함수 b의 AO 객체 2. 함수 a의 AO 객체 3. Global GO 객체. 함수 b에서 aaa를 인쇄하면 범위 체인의 맨 위에서 시작합니다. 함수 b의 AO 객체에 aaa가 없으면 범위 체인을 따라 아래로 검색하여 두 번째 수준 함수 a의 AO를 찾습니다. .aaa의 값을 123으로 구하고 그 결과를 출력하는 것이 목적입니다.
如果我们没有从预编译的角度去分析就会认为此时的aaa应该会报错的,当var demo = a()执行时,当a函数执行结束,那么a对应的AO对象应该被销毁了,照常理分析当我们执行demo时作用域链此时应该会创建b的AO对象和GO对象,此时只有b的AO对象,没有a的AO对象,应该不能打印出aaa的值,但是此时aaa的值为123,则说明a的AO对象没有被销毁,那么为什么呢?原因就在于这里创建了闭包,当var demo = a()执行结束之后,垃圾回收机制会来问,a函数老兄,我看你都执行完毕了,你的运行内存是不是可以给我释放了,但是此时a函数只能无奈摇摇头说道,老哥,我也不确定我有没有执行完毕,我执行完创建了一个b,但是b又不归我管,所以我也不确定b有没有被调用,所以我也不确定我有没有执行完毕,垃圾回收机制想了想,既然你都不知道那我就不回收了,要是回收了还没执行完的就该报错了,所以此时a的AO对象就没有被回收。
补充全面一点就是:当一个函数内部的函数被保存到函数外部时,就会产生闭包。
相信通过这两个例子,你已经对闭包有了一个大概的了解,那接下来我们说一下闭包有哪些作用。
闭包的作用
- 实现公有变量 例如:累加器(3.js)
- 做缓存
- 可以实现封装,属性私有化
- 模块化开发,防止污染全局变量
我们对闭包的作用也来一个例子(3.js)
var count = 0 function add() { return count++ } console.log(add()); console.log(add()); console.log(add());로그인 후 복사这是一段比较普通的累加的代码,但是如果我们在实习甚至是工作的时,公司要求你把累加器封装成一个模块化的代码,那么
此时,为了模块化我们尽可能避免定义全局变量,但是不定义全局变量我们如何实现呢,此时我们就可以用到闭包了;function add() { var count = 0 function a() { ++count console.log(count); } return a } var res = add() res() res() //add函数结束之后,add的AO对象没有被销毁,因为add函数执行完了之后,返回的a不知道是否被调用就形成了闭包,这样 就能使得不使用全局变量也能封装成一个模块化的累加器。로그인 후 복사结语
那么关于闭包以及闭包的作用相关的一些个人见解就是这些,目前对于闭包也只是一些浅显的了解,后期学习之后完善过后会出后续关于闭包的相关文章,感谢您的观看,欢迎批评斧正,一起共同进步。
【相关推荐:javascript视频教程、web前端】
위 내용은 폐쇄란 무엇입니까? JavaScript의 클로저에 대해 이야기하고 어떤 기능을 가지고 있는지 살펴보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!