1 0

有关闭包 事件的引用传址问题?求解答0

我们都知道javascript中的对象类型是传引用地址的而不是传值的,我今天遇到个不明白的问题就是当我把代码在点击事件写的时候令我以外的传值了,而我写到循环里面却是传的地址代码如下
这里是普通循环触发,结果是2s后三次alert,每次都是2,这是和预期的一样last给bb传递了引用地址,就是当last改变时候bb也改变了
<html>
<script>
//普通循环demo
for(i=0;i<3;i++){
        var aa = {name:"aa"};
        aa.name = i;
        last = aa;

        var bb = last;
        setTimeout(function() {
            alert(bb.name);
        }, 2000);
}
</script>
</html>
下面是事件触发 就是在2s内迅速点击鼠标3次,结果2s后三次alert依次是0,1,2。我很不解,为什么这里last传给bb的不是引用地址呢??bb为什么不改变呢?很奇怪望讨论
<html>
<script>
//事件demo
    var i = 0;
    var last = null;
    document.addEventListener("click", function(event) {
        var aa = {name:"aa"};
        aa.name = i;
        last = aa;

        var bb = last;
        setTimeout(function() {
            alert(bb.name);
        }, 2000);
        i++;
    });
</script>
</html>
2012年8月09日 14:47

2个答案 按时间排序 按投票排序

0 0

采纳的答案

我来尝试解释这个现象。

先说办法,就是把这句

 alert(bb.name); 


都改成

alert(bb.name + " - " + last.name); 


再执行,你会看到

- 循环那例子连续alert了3次“2 - 2”,
- 事件那例子分别alert了“0 - 2”,“1 - 2”,“2 - 2”。

我认为原因是,每次事件处理都有自己独立的context,其中保存了局部变量,比如bb。setTimeout中的function也是在这个context下执行的。

- 循环例子中只有一个默认的context,循环结束后bb被改成2,所以三次都是2。
- 事件的例子中先后又有了3个独立的context,每个context里面的局部变量bb分别是0,1,2。但全局变量last还都是被改成了2。所以结果如上。

我又把第二个例子改成这样
<html> 
<script> 
//事件demo 
    var i = 0; 
    var last = null; 
    document.addEventListener("click", function(event) { 
        var aa = {name:"aa"}; 
        aa.name = i; 
        last = aa; 

        var bb = last;
        var x = (i==0)?2000:1000;
        setTimeout(function() { 
             alert(bb.name + " - " + last.name); 
        }, x); 
        i++; 
    }); 
</script> 
</html>


也就是让第二次点击的timeout先到期,得到的结果是“1 - 1”,“0 - 1”这样的顺序。似乎也能验证上面的论点。

所以,这个恐怕不是值传递还是引用传递的问题,而是执行context混合作用域的问题。

2012年8月11日 16:12
0 0

最近又有看过些书籍,正式的描述应该是:“JS的作用域是由函数决定的。”

用这中说法——应该是正式的说法——来讲,

例子1:
bb是全局的,也就是window的。所以每次alert都是最终被改变的值。

例子2:
bb是function(event)这个函数的,这个函数先后被调用了三次。每次有各自的值0,1,2,其实也是当时的last这个全局变量的值。

意思差不多,不知道是否更容易理解些呢?

例子1如果写成下面这样,就会和例子2一样了。

<html>
<script>
	//普通循环demo 
	for (i = 0; i < 3; i++) {
		var aa = {
			name : "aa"
		};
		aa.name = i;
		last = aa;

		var bb = last;

		(function(cc) {
			setTimeout(function() {
				alert(cc.name);
			}, 2000);
		})(bb);
	}
</script>
</html>


也就是套个匿名函数,这样就可以留住每次的bb了。

2012年8月27日 17:22

相关推荐

    什么是闭包?闭包的优缺点?

    什么是闭包?闭包的优缺点?

    数据库求属性集闭包&函数依赖闭包

    声明:以下仅个人观点,若有错误,敬请指正O(∩_∩)O~ 关键点 1) 将函数依赖用multimap,string&gt; 存储,因为函数依赖可能...对每一个子集求其闭包,记为Ri+;然后求Ri+的所有子集记为(Ri+)j;最后做映射Rià(Ri+)j。

    c++求传递闭包

    求解传递闭包的主要方法之一是使用 Floyd-Warshall 算法,该算法可以有效地计算出所有顶点对之间的最短路径,同时也可以用来求解传递闭包问题。Floyd-Warshall 算法的基本思想是:对于任意两点 \( (i, j) \),如果...

    离散数学-关系,集合,求自反闭包,对称闭包,传递闭包

    离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包...

    计算NFA中ε闭包

    ### 计算NFA中的ε闭包 #### 一、NFA与ε闭包概念介绍 **非确定有限自动机(NFA)**是一种理论计算模型,它扩展了确定...理解并掌握了NFA和ε闭包的概念及其计算方法后,可以进一步应用于更复杂的自动机转换问题中。

    python闭包.html

    什么是闭包?如何设置闭包?创建闭包可以用来干什么?闭包的好处,如何正确使用闭包?通过闭包能创建一些只有当前函数能访问的变量,

    求闭包 属性集闭包 函数依赖的闭包

    3. 用户输入完毕所有的依赖后,显示“请输入属性集求闭包”的提示,当用户输入1个或者多个属性时,求出对应的闭包。(如,用户输入A,则显示A+的值, 用户输入AB则求出AB+的值。显示完毕后,再次显示“请输入属性集...

    关系闭包的计算

    ### 关系闭包的计算 #### 实验背景与目的 在计算机科学与数学领域中,关系闭包是一种重要的概念,特别是在图论与数据库理论中有着广泛的应用。本实验旨在通过编程实践的方式帮助学习者深入理解关系闭包的概念,并...

    利用Warshall_算法求二元关系的可传递闭包

    《利用Warshall算法求二元关系的可传递闭包》 在离散数学中,二元关系是一个重要的概念,它描述了集合中的元素之间是否存在某种特定的联系。当需要研究这些关系并探究其性质时,有时我们需要计算关系的传递闭包。...

    Swift 中的闭包和 Objective-C 中的Block

    Swift中的闭包和Objective-C中的Block是两种编程语言中实现匿名函数的关键特性,它们允许我们定义可以在不同上下文中使用的代码块。尽管这两种语言都属于Apple的生态系统,但它们在闭包和Block的概念上有细微差别。 ...

    浅谈js 闭包引起的内存泄露问题

    例如,一个DOM节点引用了一个事件处理函数,而该函数又通过闭包引用了这个DOM节点,形成闭包和DOM的循环引用,导致二者都不能被垃圾回收。 2. 由外部函数调用引起的内存泄漏:这是指外部函数在闭包中引用了变量,而...

    用矩阵求自反闭包自反闭包

    在计算机科学和图论中,自反闭包是与关系理论相关的概念,特别是在布尔代数和图的子结构分析中。自反闭包是指给定一个关系R,将其扩展为包含所有起点到自身的元素对,即对于每一个元素a,都有(a, a)属于自反闭包。这...

    百度地图API详解之事件机制,闭包机制,marker事件,信息窗口,叠加层

    在事件处理函数中,由于事件触发时可能在循环或其他上下文中,闭包用于保存和隔离变量的值,避免因作用域链的问题导致意外的结果。 3. **marker事件**:在百度地图API中,Marker对象代表地图上的一个标记,可以监听...

    离散实验报告求有限集上给定关系的自反、对称和传递闭包

    离散实验报告求有限集上给定关系的自反、对称和传递闭包 在离散数学实验报告中,我们将学习如何求有限集上给定关系的自反、对称和传递闭包。这些概念是离散数学的重要组成部分,对于理解关系闭包的性质和应用具有...

    内存泄露,闭包 内存泄露,闭包 内存泄露,闭包

    然而,当函数返回一个内部引用了外部变量的闭包时,即使外部作用域不再需要这些变量,它们也无法被垃圾回收,因为闭包仍然持有对它们的引用。这就是闭包引发内存泄露的一种常见方式。 内存问题主要分为以下几种类型...

    求传递闭包

    我自己写的求传递闭包的程序。多批评。用类封装过了。应该比较好用。

    最符合菜鸟的闭包

    7. **事件处理**:在处理DOM事件时,闭包可以防止内部函数失去对事件源的引用,例如在循环中为多个元素绑定事件监听器。 理解闭包需要时间和实践,关键在于掌握如何创建和利用闭包来解决实际问题。通过不断练习和...

    闭包问题html

    如果不再需要闭包,应确保将其设置为 `null` 来释放引用,让垃圾回收器可以回收相关资源。 总之,闭包是JavaScript中一种强大的工具,它允许我们创建持久化的、私有的变量状态,实现模块化和数据封装。理解并熟练...

    (Swift)闭包作为属性

    由于闭包可以引用其外部的实例,这就涉及到内存管理的问题。Swift使用自动引用计数(ARC)来管理内存,当一个对象被引用时,它的引用计数增加。闭包作为属性时,闭包会强引用持有它的对象,可能导致循环引用(Strong...

    JS闭包可被利用的常见场景

    JavaScript 闭包是一种强大的编程工具,常常被用来解决特定的问题和优化代码结构。在JavaScript中,闭包是指一个函数能够访问并操作其定义时的作用域内的变量,即使该函数在其外部作用域被调用。以下将详细介绍两个...

Global site tag (gtag.js) - Google Analytics