也谈JavaScript闭包
闭包对于很多JavaScript初学者来说,都是比较难以理解的一个概念。其实,闭包并不是那么难以掌握的,理解闭包,只需要学会3个的基本事实。
首先我们来看第一个事实,JavaScript允许当前函数引用外部定义的变量,如下:
function makeSandwich() { var magicIngredient = "peanut butter"; function make(filling) { return magicIngredient + " and " + filling; } return make("jelly"); } makeSandwich(); // "peanut butter and jelly"
上述代码中,函数make是可以使用magicIngredient这个变量的。这是因为,JavaScript首先会在make函数内部以及他的原型上寻找magicIngredient这个变量,结果没有找到,于是,他就会沿着词法环境(或者说是作用域链)向它上一级作用域寻找,于是,就在makeSandwich里找打了。
接下来,我们再来看一下第二个事实,即使外部函数已经返回,当前函数依然可以使用外部函数的变量:
function sandwichMaker() { var magicIngredient = "peanut butter"; function make(filling) { return magicIngredient + " and " + filling; } return make; } var f = sandwichMaker(); f("jelly"); // "peanut butter and jelly" f("bananas"); // "peanut butter and bananas" f("marshmallows"); // "peanut butter and marshmallows"
这个例子与第一个例子几乎是一样的,只是,make函数不是直接在sandwichMaker里面直接执行,而是将他返回到函数外部,然后才执行。即使函数已经返回到外部了,f函数(也即make函数,其实他们的引用是一样的)依然记住magicIngredient变量的值。
这是如何工作的呢?答案是,JavaScript的函数值包含的信息比它执行时所需要的信息还要多。而且,JavaScript函数内部存储了可能会用到的在外部定义的变量的引用(注意是引用,而不是值)。那些在其所涵盖的作用域内跟踪变量的函数称为闭包。这里的make函数就是闭包了,它引用了两个外部变量,magicIngredient和filling。每当make函数被调用时,都能够用到这两个变量,因为,他的内部已经存储了他们的引用( 指针)。
函数可以引用其作用域内的任何变量,包括参数和和外部函数变量,上面的代码可以改成如下形式,使它更为灵活通用:
function sandwichMaker(magicIngredient) { function make(filling) { return magicIngredient + " and " + filling; } return make; } var hamAnd = sandwichMaker("ham"); hamAnd("cheese"); // "ham and cheese" hamAnd("mustard"); // "ham and mustard" var turkeyAnd = sandwichMaker("turkey"); turkeyAnd("Swiss"); // "turkey and Swiss" turkeyAnd("Provolone"); // "turkey and Provolone"
JavaScript还提供了一种通过字面量来创建闭包的方法,那就是函数表达式,如下:
function sandwichMaker(magicIngredient) { return function(filling) { return magicIngredient + " and " + filling; }; }
我们会发现,这个函数表达式是一个匿名函数,但是,这并无影响的,因为,我们并没有在里面调用执行它。
最后,我们来看一下第三个事实,闭包可以更新外面变量的值。
事实上,闭包内部存储的是外部变量的引用地址,而不是外部变量的值的副本。光说是很难理解的,下面我们来看一个例子:
function box() { var val = undefined; return { set: function(newVal) { val = newVal; }, get: function() { return val; }, type: function() { return typeof val; } }; } var b = box(); b.type(); // "undefined" b.set(98.6); b.get(); // 98.6 b.type(); // "number"
这个例子,box函数可以返回一个对象,这个对象具有3个闭包,分别是set,get,type,他们都可以访问到val这个变量,其中,set是设置val的值,get是获取val的值,type是获取val的值的类型。
总结:
1.函数可以引用定义在其外部的变量
2.闭包比创建他们的函数具有更长的生命周期
3.闭包内部存储了外部变量的指针,既可以读取他们,也可以修改。
分类:
javascript
标签:
javascript
posted on 2015-11-18 17:10 ChessZhang 阅读(876) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?