JavaScript 闭包机制详解及实例代码
作者:cy012124 发布时间:2024-10-22 22:14:02
首先要区分两个概念,一是匿名函数,一是闭包。
所谓匿名函数,就是创建函数没有给定函数名。经常出现的包括函数表达式,就是定义一个匿名函数,然后将函数赋值给某个变量,而此时这个变量就相当于该函数的函数名,例如:
var sayHi = function(){
alert("Hi");
}; //注意这个分号
sayHi(); //调用函数
还有一种常用匿名函数的情况是回调函数,如 JQuery 中常用到的:
$("p").click(function(){
alert("click");
});
此外,还有利用匿名函数作为某函数的返回值:
function sayNameWithAge(age){
return function(person){
if(person.age == age){
return person.name;
}
}
}
那么,闭包又是怎么一回事呢?所谓的闭包,其实就是一个函数,而这个函数有一点比较特别,它有权能够去访问其他函数作用域的变量。
从定义中我们发现,其实在上面的匿名函数例子中,就存在这样的闭包。在最后一个例子中,匿名函数访问了函数 sayNameWithAge 的参数 age,那么,这个作为返回值的匿名函数就是一个闭包。
要彻底理解闭包,就必须理解函数调用时的整个机制,这里从作用域链的相关知识来进行讲解。
首先看下面的例子:
function sayName(name){
alert(name);
}
sayName("Jack");
在上面的函数 sayName 被调用的时候,就会创建一个对应的执行环境和作用域链,如下图所示:
当 sayName 函数被调用时,创建了相应的作用域链,而作用域中包含两个引用分别指向两个对象,其中一个是全局变量对象,这个全局对象是在函数创建的时候就已经创建了,只是在调用函数的时候才将其复制到作用域链中;而另一个就是函数的活动对象,这个对象是在调用函数的时候才创建的。
在函数中访问一个变量时,就会从作用域中搜索对应名字的变量。
而当函数执行完毕后,函数的活动对象会被销毁,而全局变量对象却永远保存在内存中。
但是,上面所说的都是普通函数的情况,对于闭包而言,又是另外一种情况:
以上面的 sayNameWithAge 函数为例:
function sayNameWithAge(age){
return function(person){
if(person.age == age){
return person.name;
}
}
}
//创建函数
var sayName = sayNameWithAge(18);
//调用函数
var name = sayName({name:"Jack",age:18});
//解除对匿名函数的引用
sayName = null;
当上面的 sayName 函数被调用的时候,产生的作用域链如下所示:
当匿名函数被 return 后,它的作用域链被创建,并且包含了外部函数的活动对象和全局变量对象,这样一来,这个匿名函数就可以访问 sayNameWithAge 函数中定义的所有变量,也就是一个闭包。
这样的闭包会存在一个问题,就是当 sayNameWithAge 函数执行完毕的时候(JS 的垃圾处理机制大多是标记清除),其活动对象被闭包所引用,所以活动对象并不会被销毁,只有当匿名函数被销毁后,sayNameWithAge 的活动对象才会被销毁,所以上面的最后一行解除对匿名函数的引用不仅是为了销毁闭包的对象,也是为了销毁外部函数的活动对象。所以,慎重使用闭包!!!
关于闭包,还有一个需要注意的地方,就是在闭包中访问其他函数的变量,实际上是因为闭包的作用域链中有指向其他函数的活动对象的引用,而不是闭包自身的活动对象中保存着这些变量。看下面的例子:
function outer(){
var result = new Array();
for(var i = 0; i < 5; i ++){
result[i] = function(){
return i;
};
}
return result;
}
按照设想,最后 outer 返回的数组各个项中的值应该是与其下标一致的。但是,最后的结果却是每个项的值都是 5
不难想象,在上面的所有闭包的作用域链中,都有一个引用指向了 outer 的活动对象中的参数 i,而且是指向同一个对象。
当 outer 函数执行完毕的时候,i 的值是 5。也就是说,所有闭包中访问 i 的时候取到的值都是 5
那么,我们可以通过另一种方法来实现预想的效果:
function outer(){
var result = new Array();
for(var i = 0; i < 5; i ++){
result[i] = (fuction(index){
return index;
})(i);
}
return result;
}
这里我们为匿名函数定义一个参数 index,并在每次循环中立即调用该函数,将 i 的当前值复制给参数 index(注意 JS 中是按值传递),并将返回的 index 赋值给 result。
此外,闭包中需要注意的另一个问题是 this 对象。
this 对象在 JS 中是在函数运行时基于函数的执行环境绑定的。而匿名函数的执行环境具有全局性,也就是说,在匿名函数中,this 对象通常指向 window。
var name = "Tom";
var person = {
name : "Jack",
sayName : function(){
return (function(){
return this.name;
})();
}
}
person.sayName(); //Tom
上面在闭包中访问 this.name,其中的 this 对象并非取得自身或是 person 的 this 对象,而是指向 window。
如果需要在闭包中访问外部函数的 this 对象,那么,可以在外部函数中定义一个变量,将 this 对象传给该变量。
var name = "Tom";
var person = {
name : "Jack",
sayName : function(){
var self = this;
return (function(){
return self.name;
})();
}
}
person.sayName(); //Jack
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
来源:http://lib.csdn.net/article/javascript/12370?knId=495


猜你喜欢
- Python使用 continue 语句跳出循环,而break跳出整个循环。continue 语句用来告诉Python跳过当前循环的剩余语句
- 起因引发原因:门店需求新增自提门店,自提门店需要加自提点图片,在渠道店上引入了图片地址img_url 的字段,字段值定义为text not
- 本篇主要记录的是利用javscript实现一个网页计算器的效果,供大家参考,具体内容如下话不多说,代码如下:首先是html的代码:<!
- 在设计主键的时候往往需要考虑以下几点: 1.无意义性:此处无意义是从用户的角度来定义的。这种无意义在一定程度上也会减少数据库的信息冗余。常常
- 其实这个问题落伍谈了n次了其中care4也说了两次所以如果你有问题最好先搜索一下 说不定问题早有人解决了http://www.im286.c
- django1.3新加入了一个静态资源管理的app,django.contrib.staticfiles。在以往的django版本中,静态资
- 脚本之家下载:JetBrains DataGrip 2020.1 免费中文正式版(附汉化包+安装教程) 最新DataGrip202
- 本文实例为大家分享了JS实现图片放大镜效果的具体代码,供大家参考,具体内容如下<!DOCTYPE html><html&g
- 前言提示:以下是本篇文章正文内容🧡基本概念🌳树的定义树是n(n≥0)个结点的有限集合,n = 0时,称为空树,这是一种特殊情况在任意一棵非空
- ptb数据集是语言模型学习中应用最广泛的数据集,常用该数据集训练RNN神经网络作为语言预测,tensorflow对于ptb数据集的读取也定义
- 一个例子: print("Loading vgg19 weights...")vgg_mode
- 一、开始工具的安装1.git安装git工具有两种方式,一种就是利用自带包管理工具,一种是源码编译安装(1)由于CentOS已经具有包管理器因
- 引言要说在工作中最让人头疼的就是用同样的方式处理一堆文件夹中文件,这并不难,但就是繁。所以在遇到机械式的操作时一定要记得使用Python来合
- 由于ajax在跨域的访问上有问题,目前最好的方法是做代理.写了个代理程序和心得为了做ajax的代理,研究了下服务器端的xmlhttp并和客户
- 环境管理管理 Python 版本和环境的工具p:非常简单的交互式 python 版本管理工具。官网pyenv:简单的 Python 版本管理
- python 调用系统ffmpeg进行视频截图,并进行图片http发送ffmpeg ,视频、图片的各种处理。 最近在做视频、图片
- 1. 游戏是更注重于体验的产品,所以应该将游戏本省做得更加炫动和增加参与感觉。2. 网络游戏和单击游戏的区别在于社会化的添加,所以运用好这样
- 功能:扫描当前目录下所有CSV文件并对其中文件进行统计,输出统计值到CSV文件pip install pandasimport pandas
- 1、使用索引来更快地遍历表。缺省情况下建立的索引是非群集索引,但有时它并不是最佳的。在非群集索引下,数据在物理上随机存放在数据页上。合理的索
- 文件操作我们可以使用python来操作文件,比如读取文件内容、写入新的内容等,因为任何计算机文件的本质都是一些有不同后缀的字符组成的。pyt