热门标签 | 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私有属性和私有方法(不能被外部访问)

使用闭包的注意点

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



推荐阅读
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 本文介绍了如何使用JQuery实现省市二级联动和表单验证。首先,通过change事件监听用户选择的省份,并动态加载对应的城市列表。其次,详细讲解了使用Validation插件进行表单验证的方法,包括内置规则、自定义规则及实时验证功能。 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 本文讨论了如何根据特定条件动态显示或隐藏文件上传控件中的默认文本(如“未选择文件”)。通过结合CSS和JavaScript,可以实现更灵活的用户界面。 ... [详细]
  • 尽管使用TensorFlow和PyTorch等成熟框架可以显著降低实现递归神经网络(RNN)的门槛,但对于初学者来说,理解其底层原理至关重要。本文将引导您使用NumPy从头构建一个用于自然语言处理(NLP)的RNN模型。 ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
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社区 版权所有