摘要:现在可以画一个基本的闭包出来了三种传递方法分开看,你可以的。二循环中的闭包说到循环闭包就要掏出大家耳熟能详的栗子了。外部包装函数返回值至少引用一个内部函数创建包装函数内部作用域闭包。
闭包 一、闭包是什么?
将一个 词法作用域 中的 内部函数 作为一个 一级值类型 到处传递,就形成了闭包。
怎么去理解呢?这里要敲黑板划重点了,上面的概念性文字介绍了三个点:
词法作用域(函数)
内部函数
一级值类型传递
1、先说词法作用域形成一个作用域最常见的就是函数了,函数内部会形成一个内部作用域,然后还有 let 、const 以及像 try/catch 结构中的 catch 分句形成的块作用域。
let 就是为其声明的变量隐式劫持了所在的块作用域,这个在后面讲 let 和闭包的时候会详细说明 let 和闭包结合的用法。
通过了解可以知道,这里的作用域其实就是函数的内部作用域。
2、内部函数内部函数不用介绍了吧,在词法作用域中定义的函数,传递后具有涵盖自身所在作用域的闭包。
3、一级值类型传递值类型传递方式有很多种啊,函数里面的一级值传递无非就是:返回值( return )、赋值( 赋值给外部变量 )、参数传递( 作为参数传递给外部函数 )。
现在可以画一个基本的闭包出来了:
//三种传递方法①②③分开看,你可以的。 var fn; //定义全局变量,用于内部赋值 ---② function foo() { var a = 2; function bar() { console.log(a); }; return bar; //返回值 ---① fn = bar; //赋值 ---② baz(bar); //参数传递 ---③ }; //定义外部函数,用于使用内部分配给全局变量的函数 ---② function cat() { fn(); }; //定义外部函数,用于内部参数传递 ---③ function baz(func) { func(); }; foo(); //2 ---① cat(); //2 ---② baz(); //2 ---③
再来一例:
function wait(message) { setTimeout(function timer(){ console.log(message); },1000); } wait("Hi Baby");
解析一下,按照我们前面的思路可以贯穿下来:
首先 wait(..) 里面的作用域,作用域内部的 timer(..)函数,再将内部函数 timer(..) 传递给内置工具函数 setTimeout(..),setTimeout(...)有参数引用( 也就是我们传递的 timer(...) ),然后调用它。
整个过程行云流水,然后词法作用域在这个过程中保持完璧之身。OK!
二、循环中的闭包说到循环闭包就要掏出大家耳熟能详的栗子了。
for(var i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); },i*1000) } 666!好!输出了几个6,老铁有点懵逼,不知应该扎心还是双击666。
为何?
你大爷还是你大爷,即使你在每次迭代都定义了函数,但是都在共享全局作用域中,i 还是这个 i
那要怎么解决?
这时候在每个迭代的时候加上一个闭包作用域,并且你得把这个 i 大爷放进作用域中。
//放法可以是传参①,可以是赋值② for(var i = 1; i <= 5; i++) { //这里先搞一个闭包作用域,派出我们的 IIFE (function(j) { // ---① setTimeout(function timer() { console.log(j); },j*1000) })(i); // ---① (function() { var j = i; // ---② setTimeout(function timer() { console.log(j); },j*1000) })(); }
上面这个是用了闭包作用域,每次迭代都生成一个新的作用域,来封闭内部变量。
说到这里,前面提到的 let 应该还有人记得,let 干嘛用的,不就是劫持变量形成块作用域吗? 放在这里不是恰到好处? 来一发。
for(let i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i) },i*1000) }
直接在定义 i 大爷的地方就 "绑架" 了他。
或者,你也可以麻烦一点,先让他上迭代车,上车之后再 let 定义一个变量把 i 大爷赋给他,两种都行,简单点好。
三、总结一下闭包应用定时器、事件监听器、Ajax请求、跨窗口通信、Web Workers 或者其他的异步(或同步)任务中(balabala~~~~),只要使用了回调函数,就是在使用闭包。
还有一处重要的 模块。
模块的两个重要特征:
有外部包装函数(创建内部作用域)且需要被调用。
外部包装函数返回值至少引用一个内部函数(创建包装函数内部作用域闭包)。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/103488.html
摘要:也许最好的理解是闭包总是在进入某个函数的时候被创建,而局部变量是被加入到这个闭包中。在函数内部的函数的内部声明函数是可以的可以获得不止一个层级的闭包。 前言 总括 :这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略。 译者 :文章写在2006年,可直到翻译的21小时之前作者还在完善这篇文章,在Stackoverflow的How do Java...
摘要:但是闭包也不是什么复杂到不可理解的东西,简而言之,闭包就是闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。可惜的是,并没有提供相关的成员和方法来访问闭包中的局部变量。 (收藏自 技术狂) 前言:还是一篇入门文章。Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态语言C/C++的程序员来说是一个新的语言特性。本文将...
摘要:当在中调用匿名函数时,它们用的都是同一个闭包,而且在这个闭包中使用了和的当前值的值为因为循环已经结束,的值为。最好将闭包当作是一个函数的入口创建的,而局部变量是被添加进这个闭包的。 闭包不是魔法 这篇文章使用一些简单的代码例子来解释JavaScript闭包的概念,即使新手也可以轻松参透闭包的含义。 其实只要理解了核心概念,闭包并不是那么的难于理解。但是,网上充斥了太多学术性的文章,对于...
摘要:深入系列第八篇,介绍理论上的闭包和实践上的闭包,以及从作用域链的角度解析经典的闭包题。定义对闭包的定义为闭包是指那些能够访问自由变量的函数。 JavaScript深入系列第八篇,介绍理论上的闭包和实践上的闭包,以及从作用域链的角度解析经典的闭包题。 定义 MDN 对闭包的定义为: 闭包是指那些能够访问自由变量的函数。 那什么是自由变量呢? 自由变量是指在函数中使用的,但既不是函数参数也...
摘要:一言以蔽之,闭包,你就得掌握。当函数记住并访问所在的词法作用域,闭包就产生了。所以闭包才会得以实现。从技术上讲,这就是闭包。执行后,他的内部作用域并不会消失,函数依然保持有作用域的闭包。 网上总结闭包的文章已经烂大街了,不敢说笔者这篇文章多么多么xxx,只是个人理解总结。各位看官瞅瞅就好,大神还希望多多指正。此篇文章总结与《JavaScript忍者秘籍》 《你不知道的JavaScri...
摘要:但是,必须强调,闭包是一个运行期概念。通过原型链可以实现继承,而与闭包相关的就是作用域链。常理来说,一个函数执行完毕,其执行环境的作用域链会被销毁。所以此时,的作用域链虽然销毁了,但是其活动对象仍在内存中。 学习Javascript闭包(Closure)javascript的闭包JavaScript 闭包深入理解(closure)理解 Javascript 的闭包JavaScript ...
阅读 2790·2021-11-24 09:39
阅读 2550·2021-11-23 09:51
阅读 1809·2021-11-17 09:33
阅读 1739·2021-10-22 09:54
阅读 1873·2021-08-16 11:00
阅读 3423·2019-08-30 15:53
阅读 1733·2019-08-30 13:19
阅读 2904·2019-08-30 12:49