最近看了几篇有关javascript闭包的文章,包括最近正火的汤姆大叔系列,还有《javascript高级程序设计》中的文章,……我看不懂,里面有些代码是在大学教科书中看都没看过的,天书一般。幸好最近遇到两本好书《ppk on javascript》和《object-oriented JavaScript》,正字阅读中,后者还没有中文版,但前者还是建议看原版,写的不复杂,有兴趣的朋友可以看看,适合想进阶的朋友。
今天就结合这两本书,用最浅显的语言和最通俗的方式谈谈javascript中的闭包,因为也是新手,所以有有误的地方请各位指出,谢谢
一. 准备知识
1.函数作为函数的参数
在学习javascript中,你始终要有一个有学习与其他语言不同的概念:函数(function)不么特殊的东西,它也是一种数据,与bool ,string,number没有什么两样。
函数的参数可以string,number,bool如:
function(a, b) {return a + b;}
但同样也可以传入函数。对你没有听错,函数的参数是函数!加入你有以下两个函数:
//把三个数翻一倍
function multiplyByTwo(a, b, c) {
var i, ar = [];
for(i = 0; i ar[i] = arguments[i] * 2;
}
return ar;
}
//把数加一
function addOne(a) {
return a + 1;
}
然后这么使用
var myarr = [];
//先把每个数乘以二,用了一个循环
myarr = multiplyByTwo(10, 20, 30);
//再把每个数加一,又用了一个循环
for (var i = 0; i
要注意到其实这个过程用了两个循环,还是有提升的空间的,不如这么做:
function multiplyByTwo(a, b, c, addOne) {
var i, ar = [];
for(i = 0; i ar[i] = addOne (arguments[i] * 2);
}
return ar;
}
这样就把函数当做参数传递进去了,并且在第一个循环中直接调用。这样的函数就是著名的回调函数(Callback function)
2.函数作为返回值
在函数中可以有返回值,但是我们一般都熟悉数值的返回,如
function ex(){
return 12
}
但你一旦意识到函数只是一种数据的话,你就可以想到同样可以返回函数。注意看下面这个函数:
function a() {
alert('A!');
return function(){
alert('B!');
};
}
它返回了一个弹出”B!”的函数。接下来使用它:
var newFunc = a();
newFunc();
结果是什么呢?首先执行a()的时候,弹出”A!”,此时newFunc接受了a的返回值,一个函数——此时newFunc就变成了那个被a返回的函数,再执行newFunc时,弹出”B!”
3.javascript的作用域
javascript的作用域很特别,它是以函数为单位的,而不是像其他语言以块为单位(如一个循环中),看下面这个例子:
var a = 1; function f(){var b = 1; return a;}
如果你此时试图想得到b的值:在firebug中试图输入alert(b)的话,你会得到错误提示:
b is not defined
为什么你可以这么理解:你所在的编程环境或者窗口是最顶级的一个函数,好像一个宇宙,但是b只是在你内部函数的一个变量,宇宙中的小星球上的一个点,你很难找到它,所以在这个环境中你不能调用它的;反之这个内部函数可以调用变量a,因为它暴露在整个宇宙中,无处藏身,同时也可以调用b,因为它就在自己的星球上,函数内部。
就上面这个例子说:
在f()外,a可见,b不可见
在f()内,a可见,b也可见
再复杂点:
var a = 1; //b,c在这一层都不可见
function f(){
var b = 1;
function n() { //a,b,c对这个n函数都可以调用,因为a,b暴露在外,c又是自己内部的
var c = 3;
}
}
问你,函数b可以调用变量c吗?不行,记住javascript的作用域是以函数为单位的,c在n的内部,所以对f来说是不可见的。
开始正式谈闭包:
首先看这个图:
假设G,F,N 分别代表三个层次的函数,层次如图所示,a,b,c分别是其中的变量。根据上面谈到的作用域,我们有如下结论:
- 如果你在a点,你是不可以引用b的,因为b对你是不可见的
- 只有c可以引用b
闭包的吊诡之处的就在于发生了如下情况:
N突破了F的限制!跑到于a同一层了!因为函数只认它们在定义时所处的环境(而不是执行时,这点很重要),N中的c仍然可以访问b!此时的a还是不可以访问b!
但是这是怎么实现的呢?如下:
闭包1:
function f(){
var b = "b";
return function(){ //没有名字的函数,所以是匿名函数
return b;
}
}
注意返回的函数可以访问它父亲函数中的变量b
此时如果你想取b的值,当然是undefined
但是如果你这么做:
var n = f();
n();
你可以取到b的值了!虽然此时n函数在f的外面,b又属于f内部的变量,但是f内部出了一个内鬼,返回了b的值……
现在大家有点感觉了吧
闭包2:
var n;
function f(){
var b = "b";
n = function(){
return b;
}
}
如果此时调用f会怎么样?那就生成了一个n的全局范围函数,但是它却能访问f的内部,照样返回b的值,与上面有异曲同工之妙!
闭包3:
你还可以用闭包访问函数的参数
function f(arg) {
var n = function(){
return arg;
};
arg++;
return n;
}
此时如果使用:
var m = f(123);
m();
结果是124
因为此时f中返回的匿名函数经过了两道转手,先给n,再赋给外面的m,但本质没有变,把定义时父函数的参数返回了
闭包4:
var getValue, setValue;
function() {
var secret = 0;
getValue = function(){
return secret;
};
setValue = function(v){
secret = v;
};
})
运行:
getValue()
0
setValue(123)
getValue()
123
这个就不用解释了吧,如果你有面向对象语言基础的话(如C#),这里的getValue和setValue就类似于一个对象的属性访问器,你可以通过这两个访问器来赋值和取值,而不是能访问其中内容
其实书中还有几个闭包的例子,但是原理用上面四个就足够了,希望能起抛砖引玉的作用,给javascript进阶者对闭包有一个更深刻的理解

JavaScript是现代网站的核心,因为它增强了网页的交互性和动态性。1)它允许在不刷新页面的情况下改变内容,2)通过DOMAPI操作网页,3)支持复杂的交互效果如动画和拖放,4)优化性能和最佳实践提高用户体验。

C 和JavaScript通过WebAssembly实现互操作性。1)C 代码编译成WebAssembly模块,引入到JavaScript环境中,增强计算能力。2)在游戏开发中,C 处理物理引擎和图形渲染,JavaScript负责游戏逻辑和用户界面。

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)