博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Javascript之匿名函数(闭包与变量)
阅读量:6340 次
发布时间:2019-06-22

本文共 2858 字,大约阅读时间需要 9 分钟。

1.闭包与变量

 JavaScript中的作用域链的机制引出了一个副作用,即闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function
createFunctions(){ 
    
var
result=
new
Array(); 
        
    
for
(
var
i=0;i<10;i++){ 
        
result[i]=
function
(){ 
            
return
i; 
        
}; 
    
    
return
result; 
var
funcs = createFunctions(); 
for
(
var
i=0; i < funcs.length; i++){ 
    
document.write(funcs[i]() +
"<br />"
); 
}

createFunction()函数返回一个数组。表面上看,似乎每个函数都应该返回自己的索引值,但事实并非如此,事实上每个函数的返回值都是10.因为每个函数的作用域链中都包含着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i。当createFunctions()函数返回后,变量i的值就是10,此时每个函数都引用着保存变量i的同一个变量对象,所以每个函数返回后都是10.

当然我们可以使用匿名函数强制使闭包的行为符合预期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function
createFunctions(){  
    
var
result=
new
Array();  
          
    
for
(
var
i=0;i<10;i++){  
        
result[i]=
function
(num){
            
return
function
(){  
            
return
num;  
        
};  
        
}(i);
    
}  
    
return
result;  
}  
var
funcs = createFunctions();  
for
(
var
i=0; i < funcs.length; i++){  
    
document.write(funcs[i]() +
"<br />"
);  
}

在重写了前面的createFunctions()函数后,每个函数就好返回各自不同的索引值了。在这里,我们没有直接把闭包赋值给数值,而是定义了一个匿名函数,并将立即执行该函数的结果赋值给数组。这里的匿名函数有一个参数num,也就是最终的函数要返回的值。在调用每个匿名函数时,我们传入了变量i。由于函数参数按值传递的,所以就会将变量i的当前值复制给参数num。而在这个匿名函数内部,有创建并返回了一个访问num的闭包。这样依赖,result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值了。

1.2关于this对象

在闭包中使用this对象会出现一些问题,this对象是运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被当作某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window(当然,在通过call()和apply()改变函数执行环境时,this指向其他对象)。

1
2
3
4
5
6
7
8
9
10
11
var
name=
"The Window"
    
var
object={ 
    
name:
"My object"
    
getNameFunc:
function
(){ 
        
return
function
(){ 
            
return
this
.name; 
            
}; 
        
    
}; 
alert(object.getNameFunc()());
//"The Window"(在非严格模式下)

以上代码创建了一个全局变量name,有创建了一个包含那么属性的对象,这个对象还包括一个方法——getNameFunc(),它返回一个匿名函数,而匿名函数又返回this.name.由于getNameFunc()返会一个函数。因此调用object.getNameFunc()()就会立即返回调用它的函数,结果就返回一个字符串。然而,这个例子返回的字符串是“The Window”,即全局name变量的值。

但是,为什么匿名函数没有取得其包含作用域(或外部作用域)的this对象呢?

每个函数在调用时,其活动对象都会自动获取两个特殊的变量:this和arguments。内部函数在搜索这两个变量时,只会搜到其活动对象为止,因此永远不肯能访问到外部函数中的这两个变量。不过,把外部作用域中的this对象保存在一个闭包能够访问的变量里,就可以放闭包访问该对象了。

1
2
3
4
5
6
7
8
9
10
11
12
var
name=
"The Window"
    
var
object={ 
    
name:
"My object"
    
getNameFunc:
function
(){ 
        
var
that=
this
;
        
return
function
(){ 
            
return
that.name; 
            
}; 
        
    
}; 
alert(object.getNameFunc()());
//"My object"

 以上代码中,我们在定义匿名函数之前,把this对象赋值给了that变量,而在定义闭包之后,闭包也可以访问这个变量,因为它们是我们在外部函数中特意声明的一个变量。即使在函数返回之后,this也仍然引用的object,所以调用object.getName()()就返回“My object”.

1.3内存泄漏

由于IE9之前的版本对JS对象和COM对象使用不同的垃圾回收历程,因此闭包在IE中会导致一些特殊的问题。具体来说,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁。

1
2
3
4
5
6
function
assignHandler(){
    
var
element=document.getElementById(
"someElement"
);
    
element.onclick=
function
(){
         
alert(element.id);
    
};
}

以上代码创建了一个作为element元素事件处理程序的闭包,而这个闭包则有创建了一个循环引用。由于匿名函数保存了对assignHandler()的活动对象的引用,因此就会导致无法减少element的引用数,也就无法回收该对象。

不过可以通过一下代码来解决。

1
2
3
4
5
6
7
8
9
function
assignHandler(){ 
    
var
element=document.getElementById(
"someElement"
); 
    
var
id=element.id;
  
    
element.onclick=
function
(){ 
         
alert(id); 
    
}; 
    
element=
null
;
}

 

转载地址:http://gchoa.baihongyu.com/

你可能感兴趣的文章
IBM服务器 不用引导盘安装方法详解
查看>>
DNS原理及其解析过程 精彩剖析
查看>>
nginx配置ssl注意事项
查看>>
JS操作Cookies
查看>>
RIP,IGRP,EIGRP,OSPF的对比总结
查看>>
中关村-DIY操作系统之替换DV2804恢复分区中的wim镜像
查看>>
ZeroTurnaround ZIP类库
查看>>
Linux 配置双机SSH信任
查看>>
Shell编程关于函数要注意的几点
查看>>
1、单机运行环境搭建之 --CentOS-6.5安装配置JDK-8
查看>>
数据可视化 方面的工具 -- 简单高效得呈现数据
查看>>
顺序结构程序代码之间的相互关系
查看>>
python excel用例123
查看>>
布隆过滤器 - URL去重,字符串去重
查看>>
chrome插件开发入门
查看>>
Azure手把手系列 3:把IT的钱花在刀刃上
查看>>
项目中copy List 数据,解决修改值后改变原值问题(SerialKiller)
查看>>
BAT及各大互联网公司2014前端笔试面试题:JavaScript篇
查看>>
续集一:我是YYF,这是我的故事
查看>>
SpringBoot文件上传异常之提示The temporary upload location xxx is not valid
查看>>