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

使用闭包的注意点

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



推荐阅读
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社区 版权所有