java 闭包 函数_JavaScripts闭包

闭包在js里面的存在就好像奥利奥冰淇淋里面的奥利奥,没了奥利奥,冰淇淋还是冰淇淋,毕竟js 就是一个你怎么写都能好好运行的好语言。可是人写的代码总是要高级484,所以好好理解闭包好么。

闭包的定义

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量

闭包的特性

1.函数嵌套函数

2.函数内部可以引用外部的参数和变量

3.参数和变量不会被垃圾回收机制回收

闭包举例

下面是一个更有意思的示例 — makeAdder 函数:

function makeAdder(x) {

return function(y) {

return x + y;

};

}

var add5 = makeAdder(5);

var add10 = makeAdder(10);

console.log(add5(2)); // 7

console.log(add10(2)); // 12

在这个示例中,我们定义了 makeAdder(x) 函数:带有一个参数 x 并返回一个新的函数。返回的函数带有一个参数 y,并返回 x 和 y 的和。

从本质上讲,makeAdder 是一个函数工厂 — 创建将指定的值和它的参数求和的函数,在上面的示例中,我们使用函数工厂创建了两个新函数 — 一个将其参数和 5 求和,另一个和 10 求和。

add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。

闭包的实用性

理论就是这些 — 可是闭包确实有用吗?闭包允许将函数与其所操作的某些数据(环境)关连起来。这显然类似于面向对象编程。在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

因而,一般说来,可以使用只有一个方法的对象的地方,都可以使用闭包。

在 Web 中,可能想这样做的情形非常普遍。大部分我们所写的 Web JavaScript 代码都是事件驱动的 — 定义某种行为,然后将其添加到用户触发的事件之上(比如点击或者按键)。我们的代码通常添加为回调:响应事件而执行的函数。

闭包的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

function f1() {

var n = 999;

nAdd = function(){

n += 1

}

function f2(){

console.log(n);

}

return f2;

}

var result = f1();

result();//999

nAdd();

result();//1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

闭包性能考量

如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。

例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。原因是这将导致每次构造器被调用,方法都会被重新赋值一次(也就是说,为每一个对象的创建)。

以下虽然不切实际但却说明问题的示例:

function MyObject(name, message) {

this.name = name.toString();

this.message = message.toString();

}

MyObject.prototype = {

getName: function() {

return this.name;

},

getMessage: function() {

return this.message;

}

};

上面的代码并未利用到闭包的益处,因此,应该修改为如下常规形式:

function MyObject(name, message) {

this.name = name.toString();

this.message = message.toString();

}

MyObject.prototype = {

getName: function() {

return this.name;

},

getMessage: function() {

return this.message;

}

};

参考备注:

阮一峰 学习Javascript闭包(Closure)

MDN Web技术文档 JavaScript 闭包

附上我的订阅号,欢迎关注,一起学前端

### Java 中的闭包函数概念与实现 #### 闭包的基本定义 在 Java 编程语言中,闭包是指一种能够捕获其周围环境中变量的特殊函数。这种机制使得内部函数即使在其外部作用域已经结束的情况下仍然可以访问并操作这些被捕获的变量[^1]。 然而需要注意的是,在 Java 的设计约束下,闭包无法通过返回值以外的方式直接向外界传递值。这意味着如果希望修改外部变量,则该变量必须声明为 `final` 或者实际上不可变(即逻辑上的 final)。这是为了防止因多线程等原因引发的数据一致性问题[^4]。 #### 使用 Lambda 表达式表示闭包Java 8 起引入了 Lambda 表达式作为简化语法的一部分来表达闭包行为。Lambda 是一种紧凑形式用于创建匿名类实例,并且它天然支持对外围上下文中局部变量的读取和引用。下面是一个简单的例子展示如何利用 lambda 实现类似闭包的功能: ```java public class ClosureExample { public static void main(String[] args) { int factor = 5; // 外部变量 // 定义一个接受整数参数并返回乘积的结果的方法 java.util.function.Function<Integer, Integer> multiplier = (input) -> input * factor; System.out.println(multiplier.apply(10)); // 输出 50 } } ``` 在这个案例里,lambda `(input) -> input * factor` 形成了一个闭包结构因为它捕捉到了名为 `factor` 的自由变量。尽管 `main()` 方法结束后,`multiplier` 对象依然保留着对 `factor=5` 这一状态的记忆[^3]。 #### 排序算法中的应用 另一个典型的场景是在集合框架内的比较器定制方面。比如我们可以通过如下方式基于某个字段对学生列表进行排序: ```java import java.util.*; class Student{ String name; double gpa; public Student(String n,double g){ this.name=n; this.gpa=g; } @Override public String toString(){ return "[Student Name:"+this.name+", GPA:"+this.gpa+"]"; } } public class SortWithClosure { public static Comparator<Student> getComparator(final String proName){ return new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { switch(proName.toLowerCase()){ case "name": return s1.name.compareTo(s2.name); case "gpa": if(s1.gpa<s2.gpa)return -1; else if(s1.gpa>s2.gpa)return 1; else return 0; default: throw new IllegalArgumentException("Unknown property "+proName); } } }; } public static void main(String []args){ List<Student> students=new ArrayList<>(); students.add(new Student("Alice",3.9)); students.add(new Student("Bob",3.7)); Collections.sort(students,getComparator("GPA")); for(var student :students ){ System.out.println(student.toString()); } } } ``` 上述代码片段展示了如何构建灵活的学生评分系统。这里的关键在于 `getComparator` 方法返回了一个新的比较器对象,而此比较器会依据传入的名字字符串决定具体按照哪个属性来进行排序。因此可以说每次调用都生成一个新的闭包[^2]。 ### 总结 虽然严格意义上讲Java并不完全具备传统意义上的闭包功能,但借助于Lambda表达式以及匿名内部类等方式可以在很大程度上模拟出闭包的效果。这不仅增强了程序的表现力同时也提高了开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值