热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java中的匿名函数结构与JavaScript中的匿名函数、立即执行函数及闭包的对比分析

在Java中,匿名函数作为一种无名的函数结构,无法独立调用;而在JavaScript中,不仅有类似的匿名函数,还有立即执行函数(IIFE)和闭包等高级特性。立即执行函数同样基于匿名函数实现,但会在定义时立即执行,而闭包则通过嵌套函数来捕获外部变量,实现数据封装和持久化。这些不同的函数形式在实际开发中各有应用场景,理解其特点有助于更好地利用语言特性进行编程。

匿名函数是没有函数名的,不能单独使用;

立即执行函数是基于匿名函数实现的,也没有函数名,会在定义后立即执行;

闭包是有权访问另一个函数作用域中的变量的函数。匿名函数、立即执行函数只要满足 有权访问另一个函数作用域中的变量 这一个条件,就成了闭包。

匿名函数

匿名函数:没有函数名的函数

匿名函数不能单独定义与使用

function foo() {

console.log('普通函数');

}

// 去掉函数名 foo

function () { // SyntaxError: Function statements require a function name

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

}

匿名函数的应用场景

用于函数表达式

作为返回值

用于定义对象方法

作为回调函数

用于立即执行函数

用于DOM元素注册事件

其他 ...

用于函数表达式

var sum = function (num1, num2) {

return num1 + num2;

};

console.log(sum(2, 3));

作为返回值

function sum(sum1, sum2) {

return function() {

return sum1 + sum2;

}

}

console.log(sum(2, 3)); // [Function]

console.log(sum(2, 3)()); // 5

用于定义对象方法

var obj = {

name: 'uakora',

age: 27,

foo: function() {

console.log(this.name + ' ' + this.age);

}

};

obj.foo(); // uakora 27

作为回调函数

setTimeout(function() {

console.log('匿名函数作为回调函数');

}, 1000);

用于立即执行函数

(function() {

console.log('立即执行函数是基于匿名函数创建的');

}());

用于DOM元素注册事件

var btn = document.querySelector("#btn");

//给按钮注册点击事件

sub.Onclick= function(){

console.log('Click event');

}

立即执行函数

立即执行函数(IIFE,Immediately-Invoked Function Expression),是一种在定义后就会立即执行的函数,其实质是一种语法。

立即执行函数的形式

两种常用形式

常用形式一:将匿名函数包裹在一个括号运算符中,后面再跟一个括号

(function () {

console.log('立即执行函数');

})(); // !!!特别说明:若此立即执行函数后面立马又跟着一个立即执行函数,一定要在结尾加分号,否则后面的立即执行函数会报错!

// 上一个立即执行函数不加分号,下行代码将报错:TypeError: (intermediate value)(...) is not a function

(function (a, b, c) { // 形参

console.log(a + b + c); // 6

})(1, 2, 3); // 实参

常用形式二:匿名函数后面跟一个括号,再将整个包裹在一个括号运算符中

(function () {

console.log('立即执行函数');

}());

(function (a, b, c) { // 形参

console.log(a + b + c); // 6

}(1, 2, 3)); // 实参

其他形式

可以用 !、+、-、~ 运算符代替常用形式一中的第一个括号

!function (a, b, c) {

console.log(a + b + c); // 6

}(1, 2, 3);

+function (a, b, c) {

console.log(a + b + c); // 6

}(1, 2, 3);

-function (a, b, c) {

console.log(a + b + c); // 6

}(1, 2, 3);

~function (a, b, c) {

console.log(a + b + c); // 6

}(1, 2, 3);

立即执行函数的作用

立即执行函数最本质的作用是:创建一个独立的作用域。利用这一功能,可以

初始化数据和页面(只执行一次)

模块化开发中,定义私有变量,防止污染全局(独立作用域)

解决闭包中的状态保存问题;(常见的一个函数内部返回多个函数,调用这些函数,打印父函数内部变量的问题)

案例分析

var liList = document.getElementsByTagName('li');

for(var i = 0; i

liList[i].Onclick= function() {

alert(i); // 结果:alert 出来的总是 6, 而不是0、1、2、3、4、5

}

}

期望结果:0、1、2、3、4、5

实际结果:alert 出来的总是 6

原因分析:没有形成独立作用域,每次点击执行函数都是去访问同一个 i 值(且是循环结束后的值 6)

解决方案:使用立即执行函数为每个 li 元素的点击事件函数创建独立作用域

var liList = document.getElementsByTagName('li');

for (var i = 0; i <6; i++) {

(function (i) {

liList[i].Onclick= function () {

alert(i); // 0、1、2、3、4、5

}

})(i);

}

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。闭包可以有函数名,也可以是匿名函数(没有函数名);

闭包形式一:直接以匿名函数的形式作为外部函数的返回值(普遍用法)

function outer() {

var n = 1;

return function() {

n++; // 访问 outer 函数作用域中的变量 n,形成闭包

console.log(n);

}

}

outer()();

闭包形式二:在外部函数内定义一个内部函数,并返回内部函数名

function outer() {

var n = 1;

function inner() {

n++; // 访问 outer 函数作用域中的变量 n,形成闭包

console.log(n);

}

return inner;

}

outer()();

闭包形式三:在外部函数内定义一个立即执行函数

function outer() {

var n = 1;

(function() {

n++; // 访问 outer 函数作用域中的变量 n,形成闭包

console.log(n);

})();

}

outer();

闭包的作用

作用一:可以直接访问函数作用域中的变量

作用二:可以将函数作用域中的变量如全局变量一样始终保存在内存中 (其实能否一直保存局部变量,跟闭包的执行形式有关)

说明:作用二的解析为个人理解

以下示例为证明观点:闭包能否一直保存局部变量,跟闭包的执行形式有关

闭包执行方式一:在返回的闭包后面紧跟一个(),立即执行

function outer() {

var n = 1;

function inner() {

n++;

console.log(n);

}

return inner;

}

outer()(); // 2

outer()(); // 2

闭包执行方式二:将返回的闭包赋值给一个全局变量,全局变量运行 ()操作,执行闭包

function outer() {

var n = 1;

function inner() {

n++;

console.log(n);

}

return inner;

}

var inner = outer();

inner(); // 2

inner(); // 3 (是在 2 的基础上加 1)

以上两种执行方式单独使用,只能说明 第二种执行方式,能使闭包一直保存局部变量,但还不能证明闭包的第一种执行方式不能一直保存局部变量,因为每次执行 outer()函数时,变量 n 都被重新初始化了。

请继续看以下代码,同时使用了闭包的两种执行方式:

function outer() {

var n = 1;

function inner() {

n++;

console.log(n);

}

return inner;

}

var inner = outer();

outer()(); // 2

outer()(); // 2 (Flag1)

inner(); // 2 (Flag2)

inner(); // 3

可以看到,Flag1 跟 Flag2 的值都是 2,假设 outer()() 这样的闭包执行方式会一直保存局部变量在内存的话,那 Flag2 处的值应该是 3。

显然假设不成立。

从而说明:闭包并非就一定可以一直保存局部变量在内存,还跟执行方式有关。

主动释放内存

function outer() {

var n = 1;

function inner() {

n++;

console.log(&#39;n = &#39;, n);

}

return inner;

}

var inner = outer();

inner(); // 2

inner(); // 3

inner = null; // 解除对闭包的引用,以便释放内存

闭包的应用场景

保护函数局部变量的安全

在内存中维持一个变量

通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)

使用闭包的注意点

由于闭包会携带 包含它的函数 的作用域,因此会比其他函数占用跟多的内存。过度使用闭包可能会导致内存占用过多



推荐阅读
  • 进程(Process)是指计算机中程序对特定数据集的一次运行活动,是系统资源分配与调度的核心单元,构成了操作系统架构的基础。在早期以进程为中心的计算机体系结构中,进程被视为程序的执行实例,其状态和控制信息通过任务描述符(task_struct)进行管理和维护。本文将深入探讨进程的概念及其关键数据结构task_struct,解析其在操作系统中的作用和实现机制。 ... [详细]
  • 本文深入探讨了 `ExpressionChangedAfterItHasBeenCheckedError` 错误的原因及其解决方案。通过分析 Angular 的变更检测机制,详细解释了该错误的发生条件,并提供了多种有效的应对策略,帮助开发者在实际开发中避免这一常见问题。 ... [详细]
  • 使用 Vue 集成 iScroll 实现移动端表格横向滚动与固定列功能 ... [详细]
  • AngularJS uirouter模块下的状态管理机制深入解析
    本文深入探讨了 AngularJS 中 ui-router 模块的状态管理机制。通过详细分析状态配置、状态转换和嵌套状态等核心概念,结合实际案例,帮助开发者更好地理解和应用这一强大工具,提升单页面应用的开发效率和用户体验。 ... [详细]
  • 在Hive中合理配置Map和Reduce任务的数量对于优化不同场景下的性能至关重要。本文探讨了如何控制Hive任务中的Map数量,分析了当输入数据超过128MB时是否会自动拆分,以及Map数量是否越多越好的问题。通过实际案例和实验数据,本文提供了具体的配置建议,帮助用户在不同场景下实现最佳性能。 ... [详细]
  • C#编程指南:实现列表与WPF数据网格的高效绑定方法 ... [详细]
  • Java 零基础入门:SQL Server 学习笔记(第21篇)
    Java 零基础入门:SQL Server 学习笔记(第21篇) ... [详细]
  • 利用Swiss数据集进行多元线性回归分析,首先通过散点图矩阵(pairs plot)初步探索各变量之间的关系。接着,绘制残差图以评估模型的拟合效果和假设条件的合理性,进一步诊断和验证模型的有效性。通过这些图形工具,可以更深入地理解模型的性能和潜在问题。 ... [详细]
  • 2019年后蚂蚁集团与拼多多面试经验详述与深度剖析
    2019年后蚂蚁集团与拼多多面试经验详述与深度剖析 ... [详细]
  • 本文提供了 RabbitMQ 3.7 的快速上手指南,详细介绍了环境搭建、生产者和消费者的配置与使用。通过官方教程的指引,读者可以轻松完成初步测试和实践,快速掌握 RabbitMQ 的核心功能和基本操作。 ... [详细]
  • 在MFC开发过程中,利用Windows内置的文件对话框可以显著提高文件操作的效率。本文总结了使用文件对话框进行文件选择和处理的经验,详细介绍了相关API的调用方法和参数设置,如`CFileDialog`类的使用、结构体`OPENFILENAME`的配置以及如何获取选中的文件路径。通过这些技巧,开发者可以快速实现文件的打开、保存等功能,提升应用程序的用户体验。 ... [详细]
  • 深入解析 AngularJS 表达式的应用与优化技巧
    本文深入探讨了AngularJS表达式的应用及其优化策略。在AngularJS中,表达式主要通过$digest循环进行自动解析,但在某些场景下,手动解析表达式也是必要的。文章详细介绍了如何利用$parse服务实现手动解析,并提供了多种优化技巧,以提高应用性能和响应速度。 ... [详细]
  • Cookie是一种小型数据文件,由Web服务器生成并存储在用户的浏览器中。当用户再次访问同一服务器时,这些数据可以被重新读取,为用户提供个性化的体验。Cookie在软件测试中具有重要作用,能够帮助测试人员验证会话管理、用户偏好设置等功能的正确性和安全性。通过深入解析Cookie的工作原理及其在不同场景下的应用,本文旨在为软件测试人员提供全面的技术指导。 ... [详细]
  • 在Linux系统中Nginx环境下SSL证书的安装步骤与WordPress CDN的高级配置指南
    在Linux系统中,Nginx环境下安装SSL证书的具体步骤及WordPress CDN的高级配置指南。首先,安装SSL证书需要准备两个关键配置文件,并建议在操作前备份相关服务器配置文件,以确保数据安全。随后,本文将详细介绍如何在Nginx中正确配置SSL证书,以及如何优化WordPress的CDN设置,提升网站性能和安全性。 ... [详细]
  • 本文深入探讨了Windows操作系统中线程同步机制的关键技术,重点分析了`WaitForSingleObject`和`Event`的使用方法及其应用场景。通过详细介绍`CreateEvent`函数的创建过程及其在判断线程退出和实现线程间同步中的重要作用,结合具体实例,展示了如何高效地利用这些工具来解决多线程编程中的常见问题。此外,文章还讨论了这些机制在实际开发中的最佳实践和注意事项,为开发者提供了宝贵的参考。 ... [详细]
author-avatar
香樟树1016
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有