好程序员前端教程之JavaScript闭包和匿名函数的关系详解

简介: 好程序员前端教程之JavaScript闭包和匿名函数的关系详解本文讲的是关于JavaScript闭包和匿名函数两者之间的关系,从匿名函数概念到立即执行函数,最后到闭包。下面一起来看看文章分析,希望你会喜欢。

好程序员前端教程之JavaScript闭包和匿名函数的关系详解
本文讲的是关于JavaScript闭包和匿名函数两者之间的关系,从匿名函数概念到立即执行函数,最后到闭包。下面一起来看看文章分析,希望你会喜欢。
前面讲了一篇在for循环中加setTimeout输出内容,我们用到了一个闭包,但同时也可以说是匿名函数,到底匿名函数和闭包有没有关系呢?【答案是它们之间没有关系】
匿名函数
匿名函数,顾名思义,就是没有名字的函数,与之对应的就是有名字的函数,也叫具名函数。
//匿名函数
function (){

console.log('匿名函数');

}
//具名函数
function myFn(){

console.log('具名函数');

}
//变量a就是匿名函数的名字
var a = function(){

console.log('a就是匿名函数的名字');

}
如果我们直接在控制台中运行匿名函数,会发现报错,无法执行。匿名函数是无法执行的,一般用到匿名函数的时候都是立即执行,也叫自执行匿名函数或者自调用匿名函数,一般人都叫立即执行函数。
立即执行函数
比较常见的立即执行函数如下:
;(function(){

console.log('caibaojian.com');

})()

;(function(){

console.log('caibaojian.com');

}());
上面这两种都是典型的立即执行函数写法,两者的区分就是一个执行在匿名函数括号外面,另外一个发起执行的括号在匿名函数里面。比较常见的是第一种写法,括号在匿名函数的括号外面。
步骤分解:
1.首先声明一个匿名函数 function(){alert('我是匿名函数')}。
2.然后在匿名函数后面接一对括号 (),调用这个匿名函数。
那为什么还要用一个括号包起来呢?其实是为了兼容JS的语法,如果我们不加括号,直接写成
function (){alert('我是匿名函数')}()
浏览器会报语法错误,想要通过浏览器的语法检查,必须加点小东西,比如下面几种
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
实际上,立即执行函数的作用只有一个:创建一个独立的作用域,在这个作用域里面,外面访问不到,避免变量污染。比如我们前面的一篇文章,setTimeout的第三个参数里面讲到的一道题目。
for(var i=0;i<6;i++){

setTimeout(function(){
    console.log(i); //为什么输出的总是 6,而不是0,1,2,3,4,5
},i*1000);

}
我们发现上面这个定时器总是输出6,因为setTimeout里面的执行函数是异步的,执行的时候,i的值是贯穿整个作用域的,而不是单独一个给每个定期器分配了一个i,for运行完的值是6,此时输出就总是6了。
那怎么解决呢?用立即执行函数给每个定时器创造一个独立作用域即可。
for(var i=0;i<6;i++){

(function(j){
    setTimeout(function(){
        console.log(j);
    },j*1000);
})(i);  

}
在for循环执行时,立即执行函数就已经有了结果了。而每个立即执行函数里面的j值就是独立的一个,不会受后面影响。所以会分别执行5次定时器。
//第一个立即执行函数
(function(0){

setTimeout(function(){
    console.log(0);
})

})(0);
//第二个立即执行函数
(function(1){

setTimeout(function(){
    console.log(1);
})

})(1);
//……
//第六个立即执行函数
(function(5){

setTimeout(function(){
    console.log(5);
})

})(5);

i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 j 「分别」是 0、1、2、3、4、5。
上面说了这么多关于匿名函数和立即执行函数的,相信你对这两个概念已经很清楚,那么闭包跟匿名函数有关系吗?
闭包
js闭包是指有权访问另一个函数作用域中的变量的函数,个人认为js闭包最大的用处就是防止对全局作用域的污染。闭包最神奇的地方就是能在一个函数外访问函数中的局部变量,把这些变量用闭包的形式放在函数中便能避免污染。
我们可以分离出上面的第一个立即执行函数
function box(i){

setTimeout(function(){
    console.log(i);
},i*1000);

}
box(1);

//或者这样
function box(i){

function inner(){
    console.log(i);
}
return inner;

}
var outer = box(1);
outer();
结论
很明显这是一个闭包,然后我们再看看我们最前面的匿名函数代码和立即执行函数代码,可以看出匿名函数和闭包两者并没有关系。闭包既可以在匿名函数也可以在具名函数中使用。
这个for循环中的闭包怎么理解以及自执行匿名函数的作用:
这个for循环产生的闭包其实是定时器的回调函数,这些回调函数的执行环境是window,类似刚才例子中的引用inner的全局outer的执行环境,匿名函数则相当于刚才例子中的box函数。
Stackoverflow网站上的一个提问跟我们今天分析的类似。有一个回答挺好。
闭包机制适用于所有JavaScript函数,无论是否匿名。
我认为这两个概念之间的混淆来自于使用术语“闭包”,其中作者已经说过“下面的代码创建一个闭包”,然后给出了一个恰好使用匿名函数的例子。 在这种情况下,闭包机制通常是使特定代码段按预期工作的重要因素,而使用匿名函数而不是命名函数恰好是编码它的便捷方式。 阅读这些例子并且第一次看到“闭包”的人然后误解了这个术语,并继续在他们自己的Stack Overflow或博客文章中错误地使用它,因此混乱传播。
一开始我以为匿名函数跟闭包有关系,那是因为恰好这个定时器使用了闭包和匿名函数,让我们误认为两者之间有关系,其实还有很多种方法可以解决这个问题,比如我们之前说到的setTimeout的第三个参数,同样可以得到跟使用立即执行函数同样的效果。
所以说匿名函数和闭包之间没有什么关系,只不过很多时候在用到匿名函数解决问题的时候恰好形成了一个闭包,就导致很多人分不清楚匿名函数和闭包的关系。

相关文章
|
2月前
|
前端开发 JavaScript 安全
从前端性能优化角度谈JavaScript代码压缩与混淆
本文从前端性能优化的角度出发,探讨了JavaScript代码压缩与混淆的重要性及实现方式,通过分析不同压缩混淆工具的特点和效果,为开发者提供了实用的指导和建议。
|
22天前
|
人工智能 前端开发 JavaScript
【前端设计】HTML+CSS+JavaScript基本特性
【前端设计】HTML+CSS+JavaScript基本特性
|
1月前
|
前端开发 JavaScript 程序员
推荐给前端程序员的5款浏览器插件
推荐给前端程序员的5款浏览器插件
|
1月前
|
前端开发 JavaScript UED
前端开发的魔法:CSS动画与JavaScript的完美结合
本文将探讨如何利用CSS动画和JavaScript的结合,为前端页面增添生动的效果。我们将通过实例展示如何使用这两种技术为网页元素创建吸引人的动画效果,并讨论它们的优缺点和适用场景。
29 0
|
1月前
|
机器学习/深度学习 人工智能 前端开发
【前端】JavaScript简介
【前端】JavaScript简介
17 0
|
1月前
|
Rust 前端开发 JavaScript
前端技术的未来:WebAssembly与JavaScript的融合之路
【2月更文挑战第12天】本文旨在探讨WebAssembly(以下简称Wasm)与JavaScript(以下简称JS)的结合如何为前端开发带来革命性变化。传统上,JS一直是前端开发的核心,但随着Wasm的出现,我们看到了前端性能和功能的新天地。文章首先介绍Wasm的基本概念,然后分析其对前端开发的影响,包括性能提升、新功能实现以及开发模式的变化。最后,探讨了Wasm与JS融合的未来趋势,以及这种融合如何推动前端技术的进步。
|
1月前
|
Rust 前端开发 JavaScript
探索前端技术的未来:WebAssembly与JavaScript的融合之路
【2月更文挑战第12天】 随着Web技术的不断进步,前端开发正迎来一场革命性变革。本文将深入探讨WebAssembly(以下简称Wasm)与JavaScript(以下简称JS)的结合如何为前端开发带来前所未有的性能提升与新的编程模式。我们将从两者的基本概念入手,探索它们各自的优势与局限,然后深入分析Wasm和JS协同工作时能够解锁的潜力,最后展望这一技术趋势如何塑造未来的前端开发生态。本文旨在为前端开发者提供洞见,帮助他们理解并准备好迎接这一即将到来的技术浪潮。
|
1月前
|
Rust 前端开发 JavaScript
前端技术的未来演进:WebAssembly与JavaScript的深度融合
【2月更文挑战第11天】 在数字化时代,前端技术的迅速发展不仅推动了用户体验的革新,也促进了Web应用的性能提升。本文将探讨WebAssembly(以下简称Wasm)与JavaScript(以下简称JS)之间的深度融合如何成为前端技术发展的关键转折点。不同于传统的技术文章摘要,我们将通过一种叙事式的预览引导读者进入这一技术领域的探索之旅,揭示Wasm和JS结合后为前端开发带来的无限可能性和挑战。
|
1月前
|
数据可视化 前端开发 定位技术
ECharts前端教程
ECharts前端教程
48 3
|
2月前
|
前端开发 JavaScript
前端 JavaScript 与 HTML 怎么实现交互
前端 JavaScript 与 HTML 怎么实现交互