西北马二最代码的gravatar头像
西北马二最代码 2017-11-16 16:34:46
javascript闭包学习(Closure)

版权声明:本博文为博主原创文章,转载时请注明出处。

1、前言:

    JavaScript的闭包是该语言的一个学习难点,要理解闭包并且掌握如何使用它,首先要理解JavaScript另一个主要的概念---作用域。

    我们都知道,JavaScript的作用域为全局变量与局部变量,一个函数体中,在函数内部声明的变量能够访问调用其外部的变量,但是在函数体外部,就无法对函数体内部的变量进行操作,显然这是很不合常理的,因为我们很多比较复杂的操作都需要调用各种形式的作用域变量,那么,我们就需要寻找一个方法来解决这个问题,而这个办法就是“闭包”。

    很多地方对于闭包的概念解释都很深奥,所以一直搞不清楚到底什么才是闭包,其实说白了,闭包就是可以读取其他函数内部变量的函数。

2、全局变量和局部变量

//全局变量
var num = 666;
function readNum(){
	alert(num);
}

//调用方法
readNum(); //666 

    在上面这个例子中,因为num是在方法体外部声明的,所以可以在方法体内部进行访问,所以这里进行方法调用后,可以输出666。

//局部变量
function readNum(){
	var num = 666;
}
//在方法体外部调用方法体内部声明的变量
alert(num);  //error

    在上面这个例子中,在函数体外部进行变量输出时,是会产生错误的,因为作用域的问题,在函数体内部声明的变量,是无法被调用的,究其根本原因,是因为函数体执行完后,函数生命周期已经结束,函数体内部的变量已经被垃圾回收机制处理掉了,所以无法进行调用。

3、那现在就出现了一个问题,我们到底该如何从外部读取到局部变量?接下来我们看这段代码

//函数体1中创建第二个函数体2
function h1(){
	var num = 666;
	function h2(){
		alert(num);  //666
	}
}

    在上面这段代码中,我们在h1中定义了一个局部变量num,并为其赋值666,在h1中再次创建函数体h2,这个时候,函数体h1内的所有变量对于h2来说都是可见的,但是反过来的话就不行,h2中的局部变量超出h2的作用域是无法访问到的,其对h1是不可见的,这也是JavaScript语言特有的“链式作用域”结构,其主要的思想就是,子对象可以一级一级的向上访问到自己的父对象,父对象内的变量数据对于子对象都是可见的,反之则不成立!

    在子对象中可以访问到父对象内的变量和数据,那么我们将h2作为返回值,那么我们在函数体外部不是也可以访问到函数体内部的局部变量了吗?大家看下面的代码

//将h2作为返回值
function h1(){
	var num = 666;
	function h2(){
		alert(num);
	}
	return h2;
}

//进行函数体外部的调用,检测结果
var n = h1();
n();   //666

javascript闭包学习(Closure)

4、那么到底什么是“闭包”?

    在上一节代码中,我们在函数体h1中创建的函数体h2就是闭包,哈哈!

    因为在JavaScript语言中,只有在函数内部定义的子函数才能访问到局部变量,所以可以说,“闭包就是在一个函数内部定义的函数”,这样讲的话,我们可以将“闭包”想象成一座联通函数体内部和函数外部的“桥梁”。

  “闭包”除了能够在起到在函数外部读取局部变量的作用外,它还能够确保函数的这些变量的值永远的保存在内存中。

//闭包的两个用途
function h1(){
	var num = 666;
	changeTo = function(){
		var b = num;
		b.toString();
	}
	function h2(){
		alert(num);
	}
	return h2;
}
//进行函数调用
var n = h1();
n(); //666
changeTo();
n();  //"666"

    这段代码中,函数n()相当于函数h2的闭包,这里的n()执行了两次,所以这里输出了两次不同的结果。

    那么为什么说“闭包”可以确保函数内的局部变量的值永远的保存在内存中呐,这是因为这里的h2被赋给了一个全局变量,这导致h2一直存在于内存中,而h2的存在依赖于h1,所以h1函数体也一直存在于内存中,所以导致了h1内部的变量也一直保存在内存中。

    这里的changeTo函数,它是一个全局变量,而非局部变量,更是一个“匿名函数”(anonymous function),而这个匿名函数本身也是一个闭包,它可以在函数外部对函数内部的局部变量进行操作。

5、使用闭包有哪些需要注意的东西?

    5.1、由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过度,造成网页的性能问题,甚至于在IE浏览器中会导致内存泄漏。对于这样的现象,我们可以在函数退出前,将不用的局部变量进行删除。

    5.2、闭包会在父函数的外部改变父函数内部变量的值。


打赏

已有1人打赏

最代码官方的gravatar头像
最近浏览
最代码-宋家辉  LV61 2021年2月25日
jyst_h5 2019年2月27日
暂无贡献等级
wkc  LV21 2018年4月9日
lw2192213158  LV1 2018年4月1日
自丶渡  LV3 2017年12月21日
马小跳  LV12 2017年12月15日
liuwen_7777  LV8 2017年12月1日
奋青员  LV12 2017年12月1日
dkhfirst  LV8 2017年11月27日
易阳羽  LV9 2017年11月24日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友