9 JavaScript闭包

9 闭包

我们都知道,函数里是可以访问函数外的全局变量,而函数外不能访问函数内的局部变量,如下:

// 函数外定义a,在函数内可以访问
var a = "测试";
function fn() {
    console.log(a);
}
fn();

执行结果:

// 函数内定义a,在函数外访问不到
function fn() {
    var a = "测试";
}
console.log(a);

执行结果:

之所以出现这样的情况,就是因为函数内定义的变量为局部变量,函数外定义的变量为全局变量(不同于windows)。在函数内部可以访问到全局变量,而在函数外部是无法访问到函数内部的局部变量的。
接下来,我们先看一段代码:

let name = "水木年华";
function fn() {
    name = "张杰";
}
fn();
console.log(name);	// 张杰

由此可知,在函数内部想要修改外部的变量是十分容易的一件事. 尤其是全局变量. 这是非常危险的. 试想, 我写了一个函数. 要用到name, 结果被别人写的某个函数给修改掉了. 多难受.
接下来,我们来看一个例子:
比如目前有一个项目,需要两个人一起开发,分别是小明.js和小芳.js
小明.js:

var key = '小明的key';
function jiami() {
	console.log("小明使用", key, "来加密");
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="小明.js"></script>
    <script>
        fn();   // 小明使用 小明的key 来加密
    </script>
</head>
<body>
</body>
</html>

小芳.js:

var key = '小芳的key';
function jiami() {
	console.log("小芳使用", key, "来加密");
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="小芳.js"></script>
    <script>
        fn();   // 小芳使用 小芳的key 来加密
    </script>
</head>
<body>
</body>
</html>

两个人的代码在各自执行的时候都没有问题,但是当把两个js文件同时在一个html文件中引用时,就会出现变量值被修改的问题:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="小明.js"></script>
    <script src="小芳.js"></script>
    <script>
	/*两个人都叫jiami,怎样区分调用的是谁的方法?*/
        jiami();
		jiami();
    </script>
</head>
<body>
</body>
</html>

执行结果:


很明显,两个脚本在同一个html文件中被引用时,变量名和函数名重复,是不是觉得让各自的变量名和函数名不一致就可以了?如下:
小明.js:

var xiaoming_key = '小明的key';
function xiaoming_jiami() {
	console.log("小明使用", xiaoming_key, "来加密");
}

小芳.js:

var xiaofang_key = '小芳的key';
function xiaofang_jiami() {
	console.log("小芳使用", xiaofang_key, "来加密");
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="小明.js"></script>
    <script src="小芳.js"></script>
    <script>
        xiaoming_jiami();
        xiaofang_jiami();
    </script>
</head>
<body>
</body>
</html>

执行结果:


这样搞确实可以实现了哈。但是问题来了,这个项目用到的变量和函数少,js脚本也少。而在真正的羡慕中,一个html文件可能引用几十个js文件,每个js文件又有成百上千的变量或者函数,这样的话我在一个一个的去修改变量名和函数名?不太现实,况且在html文件中引用的时候也不方便。那么现在这种情况,我们就可以尝试一下闭包了,比如小明和小芳之前的js代码是在一个函数中的:
小明.js:

function ming() {
	/*
	在外面在套一层函数结构,使key变量和jiami函数的作用范围由之前的全局变为ming函数的局部作用域
	*/
	var key = '小明的key';
	function jiami() {
		console.log("小明使用", key, "来加密");
	}
	return jiami;	// 最后在返回函数名供外部使用
}
ming_jiami = ming();	// 这里的ming_jiami要与小芳的进行区分

小芳.js:

function fang() {
	var key = '小芳的key';
	function jiami() {
		console.log("小芳使用", key, "来加密");
	}
	return jiami;
}
fang_jiami = fang();	// 小芳这里的fang_jiami也要与小明区分
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="小明.js"></script>
    <script src="小芳.js"></script>
    <script>
        ming_jiami();    // 小明
        fang_jiami();    // 小芳
    </script>
</head>
<body>
</body>
</html>

执行结果:


现在执行结果确实没有问题了,两个人的脚本都可以正常使用了。但是两个人外层的函数还是有可能是一样的,我们再用之前学过的匿名函数再优化一下:
小明.js:

ming_jiami = (function(){
	var key = '小明的key';
	function jiami() {
		console.log("小芳使用", key, "来加密");
	}
	return jiami;
})();

小芳.js:

fang_jiami = (function () {
	var key = '小芳的key';
	function jiami() {
		console.log("小芳使用", key, "来加密");
	}
	return jiami;
})();
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="小明.js"></script>
    <script src="小芳.js"></script>
    <script>
        ming_jiami();    // 小明
        fang_jiami();    // 小芳
    </script>
</head>
<body>
</body>
</html>

执行结果:


OK,至此,就完美的优化了这个代码。在最外面接收内部返回的参数的变量两个人重复的的几率就已经非常低了。何为闭包? 上面这个就是闭包。相信你百度一下就会知道,什么内层函数使用外层函数变量。什么让一个变量常驻内存,等等。其实你细看,它之所以称之为闭包~,它是一个封闭的环境,在内部,自己和自己玩儿,避免了对该模块内部的冲击和改动,避免的变量之间的冲突问题。

闭包的特点:

  • 内层函数对外层函数变量的使用
  • 会让变量常驻与内存

这俩玩意就不解释了,和python的闭包是一个意思。不懂没关系,能看懂他的执行过程就好。

热门相关:冉冉心动   未来兽世:买来的媳妇,不生崽   豪门情变,渣总裁滚远点!   本法官萌萌哒   买妻种田:山野夫君,强势宠!