java 匿名内部类 js 闭包

最近在看js,看到closure(闭包)这一块儿的时候就想到了 java的匿名内部类 两者都有涉及到变量/参数的引用问题。

先说java的匿名内部类,他的定义我就不多做说明了,可以参考地址

http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html

。我们今天主要说:

1、Why cannot an anonymous class access local variables in its enclosing scope that are not declared as final or effectively final.

为什么java匿名内部类的方法中用到的局部变量必须定义成final或者是无修改的(实际上也是final的)

2、js的闭包又是什么,和参数引用又有什么关系

在说明这两个问题之前,我们必须先知道几个概念就是变量的scope(作用域)和lifetime(生命周期)。scope是针对编译期,包含变量的block(块,花括号)内。而生命周期则是指程序在运行时,给变量在内存上从分配空间到释放的整个时期。

一般来说,局部变量(local variable)都是分配在stack(栈)上的,在方法运行完后随着stack的坍塌,局部变量所占用的内存也随之释放

那么我们先来说第二个问题:

var quo = function (status) {
return {
get_status: function ( ) {
return status;
}
};
};
// Make an instance of quo.
var myQuo = quo("amazed");
document.writeln(myQuo.get_status( ));

对js来说,函数内部可以直接读取全局变量,而在函数外部自然无法读取函数内的局部变量。出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,一般情况下,这是办不到的,只有通过变通方法才能实现。js里的这种机制就叫闭包(closure)。上述代码就是一个闭包,我的理解是,闭包就是能够读取其他函数内部变量的函数(英文文档的解释可能更准确)。通过闭包,上述代码中,局部变量status的lifetime延长,其内存并没有随着函数quo()的完成而被释放。其底层的实现机制可能类似于是,将closure捕捉的局部变量放在堆上而不是栈上。

然后说说第一个问题:

public Runnable f(int x) {
	int i = 0;
	Runnable r = new Runnable() {

		@Override
		public void run() {
			System.out.println(i);
			i = 10;
		}
	}

	i = 100;
	return r;
}

在java中,一般来说,在方法执行完后,其方法内的局部变量也随之释放。而当java匿名内部类的方法中用到局部变量时,使用的是变量的copy,而不是变量本身,所以为了在方法执行完以后,这个局部变量的copy没有被释放掉,这个局部变量的copy就没有被分配到这个方法的栈上,而是分配到对上,从而延长了他的lifetime。(参看上述java代码例子)而之所以要求变量是final的其实是要求该局部变量是不可变的,因为当局部变量i改变时,而匿名内部类r已经返回,而r拿到的是i原来值(i=0)的copy,i后来的值得改变,r是不知道,那r的存在就没有太多的实际意义,这显然是不合适的。所以java为了克服这个问题,就规定java匿名内部类的方法中用到的局部变量必须是不能修改的(即要么定义为final类型的,要么是在方法内不是不修改的),这样方法内局部变量和java匿名内部类的方法中用到的局部变量就保持了一致。有没有种是js阉割版闭包的感觉~

注:之所以把这两个问题放在一起说,只是因为他们在解决问题上的思路是上有相同之处。并不是说java和js有很多的相同之处。即使在这闭包这个问题上,也能看出js和java这两门语言之间很大的一个不同点,js闭包中内部函数访问的是局部变量本身,而java匿名内部类的方法中用到的局部变量则是局部变量值的拷贝。希望本文没有给你造成这种js与java类似的误解。

更多关于JavaScript 的closure的可以看看:http://www.jb51.net/article/24101.htm

时间: 2024-11-02 23:50:21

java 匿名内部类 js 闭包的相关文章

为什么说Java匿名内部类是残缺的闭包

前言 我们先来看一道很简单的小题: public class AnonymousDemo1 { public static void main(String args[]) { new AnonymousDemo1().play(); } private void play() { Dog dog = new Dog(); Runnable runnable = new Runnable() { public void run() { while(dog.getAge()<100) { // 过

java内部类之js闭包

前言: 今天写了一个关于Java内部的博客,在内部类的最后一点中谈到了Java闭包的概念,他是这样定义闭包的:闭包是一个可调用的对象,它记录了一些信息,这些信息来自创建它的作用域.结合Java的内部类可以很好的理解这一点(如有需要可参考https://www.cnblogs.com/jinliang374003909/p/10351877.html).突然之间想到js中的闭包,一直都无法很好的理解,故借此又看了一下js中的闭包,对我个人而言,感悟良多,借此也与大家分享一下,希望可以帮助大家,并一

React Native Android 源码框架浅析(主流程及 Java 与 JS 双边通信)

[工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果.私信联系我] 1 背景 有了前面<React Native Android 从学车到补胎和成功发车经历>和<React Native Android Gradle 编译流程浅析>两篇文章的学习我们 React Native 已经能够基本接入处理一些事情了,那接下来的事情就是渐渐理解 RN 框架的一些东西,以便裁剪和对 RN 有个更深入的认识,所以本篇总结了我这段时间阅读源码

js闭包浅了解

js闭包浅理解 要理解闭包,得先知道js的变量作用域,在js中,有两种变量作用域: 全局作用域 局部作用域 一.在函数内可以访问全局变量 比如,下面的例子: <!--lang:js--> <script> var n = 100; function f1(){ console.log(n); } f1()//返回100 </script> 上面的例子很简单,下面是另一种情况. 二.在函数外无法读取函数内的局部变量 还是一个小例子: <!--lang:js-->

本地java代码和javascript进行交互(java和js互调)

在android的开发过程中,有很多时候需要用到本地java代码和javascript进行交互.android对交互进行了很好的封装,在开发中我们可以很简单的用java代码调用webview中的js,也可以用webview中的js来调用本地的java代码,这样我们可以实现很多原来做不了的功能,比如点击网页上的电话号码后,手机自动拨打电话,点击网页中的笑话,自动发送短信等. 废话不多说,这次教程的目标如下 android 中的java代码调用webview里面的js脚本 webview中的js脚本

[掌眼]iOS / Android / java / node.js 通用的 AES256 加解密算法

example.m NSString *text = @"text"; NSString *key32 = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding]; NSString *encryptedData = [[data AES256EncryptWithKey:key32] base64EncodedStringWi

[工具篇]eclipse 中设置 Java/JSP/JS/HTML/CSS 智能提示

Visual Studio 2010 中的智能提示很好用,在eclipse中是否也可以通过设置使得java代码文件.jsp文件.html文件.css文件.js文件时也能有这样方便的智能提示呢?应该是有的: 1.设置java代码智能提示 1)打开eclipse→Windows→Preferences→Java→Editor→Content Assist 2)修改Auto Activation triggers for java的值为:zjava   点击apply按钮.(zjava主要是用在后面替

js闭包的作用

js闭包的用途详解 js闭包可以用在许多地方.它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中.具体怎么理解呢,各位看官请仔细看好下文 我们来看看闭包的用途.事实上,通过使用闭包,我们可以做很多事情.比如模拟面向对象的代码风格:更优雅,更简洁的表达出代码:在某些方面提升代码的执行效率. 1 匿名自执行函数 我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用

浅谈JS闭包中的循环绑定处理程序

初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript的闭包特性. 前几天工作中写前端js代码时,遇到了遍历元素给它添加单击事件. (PS:之前也在<jQuery基础教程>第四版中看过讲循环绑定处理程序的内容,当时估计也没怎么用心看,所以没记起来.) 大神要是知道这类情况,可以关掉窗口,写这些主要是给像我一样的小白看的,谢谢! 先贴上错误的例子让大家