js中闭包的理解

在了解闭包之前,我们还有一些内容需要提前了解

作用域

作用域分为,全局作用域和局部作用域。全局变量拥有全局作用域,在js代码中的任何地方都是有定义的。而在函数内声明的变量只是在函数内有定义,这就是局部变量。

全局变量顾名思义就是在整个项目中都能被调用,而局部变量就是在函数内定义,且只能在函数内能被使用,函数结束后,局部变量也就消失了。

注:如果在函数内声明一个局部变量和全局变量重名,那么局部变量的优先级高于同名的全局变量,全局变量会被局部变量所覆盖。

为什么局部变量优先级高于同名的全局变量?这就是作用域链所要回答的问题了

作用域链

每一段JavaScript代码(全局代码或函数)都有一个与之关联的作用域链,这个作用域链是一个对象列表或者链表。当某个函数被调用时,会创建一个执行环境及相应的作用域链,作用域的前端始终都是当前执行的代码所在环境的对象中。当某个环境要读取或写入而引用一个标识符时,必须通过搜索来确定带标识符实际代表什么。搜索过程从作用域的前端开始,向上逐级查询与给定名字相匹配的标识符,如果找到了,就会他停止查询。在不包含嵌套体的函数体内,作用域上只有两个对象:第一个是定义函数参数和局部变量的对象,第二个是全局对象。所以,如果局部变量和全局变量的标识符相同时,在函数内最近匹到是局部变量,如果想要对全局变量进行调用,那么只能用window.标识符进行调用;
作用域链的用途是:保证对执行环境有权访问的所有变量和函数的有序访问。

接下来让我们进入正题吧

什么是闭包

在JavaScript高级程序语言(3)中,是这样写的,闭包是指有权访问另一个函数作用域中的变量的函数。

在JavaScript权威指南中,是这样写的,函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。

所以,从技术角度讲,所以JavaScript函数都是闭包。创建闭包的常见方式,就是在一个函数内部创建另一个函数,例如:

function create(propertyName){
	return function(object1,object2){
		var value1 = object1[propertyName];
		var value2 = object2[propertyName];
		
		if(value1>value2){
			return 1;
			}else if (value1<value2){
			return -1}else{
			return 0;
			}
		}
}
//创建函数
var compareName = create("name");
//调用函数
var result = compareName({name: "xiaoli"},{name : "xiaoming"});
//解除对匿名函数的引用(释放内存)
compareName = null;

这两行代码访问了外部函数中的变量propertyName,即使这个内部函数被返回了,而且在其他地方被调用了,但它仍然可以访问到变量propertyName。这是因为内部函数的作用域链中包含create()的作用域,所以这个匿名函数(代码中return返回的函数)是一个闭包。
这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数。它就不会被当做垃圾回收。当create()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然留在内存中;直到匿名函数被销毁后,create()的活动对象才会被销毁。

当调用函数时闭包所指向的作用域链和定义函数时的作用域链不是同一个作用域链

function counter(){
var n = 0;
return {
	count: function(){ return n++; }
	reset: function(){ n = 0; }
	}
}

var c = counter(), d=counter();
c.cout()	// =>0
d.cout()  // =>0	两个count相对独立,互补干扰。
c.reset()	// 重置c里面的count
c.count()	// =>0,因为重置了c
d.count()	// = > 1,而没有重置d

每次调用counter()都会创建一个新的作用域链和一个新的私有变量。因此,如果调用counter()两次,则会得到两个计算器对象,而且彼此包含不同的私有变量,调用其中一个计数器对象的cout()或reset()不会影响到另一个对象。

闭包与变量

作用域链这种配置机制有一个很值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值,因为闭包所保存的是整个变量的对象,而不是某一个特殊的变量。例如下面这个例子:

function create(){
	var result = new Array();
	for (var i=0; i<10; i++){
		result[i] = function(){
			return i;
		}
	}
}

这个函数会返回一个数组,表面上看,似乎应该是返回内容是1-10的数组,但实际上,是内容为10个10。因为每个函数的作用域链中都保存着create()函数的活动对象i,当create()函数返回后,变量i的值是10,此时匿名函数,引用变量i,但是函数内并没有定义变量i,由于顺着作用域链往上找,在create()函数中有定义变量i,此时的变量i=10;所以这个函数返回的不是1-10,而是10个10。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值