js闭包的作用和应用的学习

什么是闭包,闭包的作用是什么?

闭包的原理:原本在函数外部是无法访问函数内部变量的,假定函数a中有变量N=1,我们可以在函数a中创建函数 c,函数c对函数a中的变量N是可以访问的,那我们可以在函数a外部通过执行调用(函数c在函数a中被return出来了)函数c调用变量N,总的来说就是通过嵌套的子函数访问函数的内部变量.即可写成(function(){ })()来快速实现闭包

闭包的应用:防止变量命名冲突\保存部分动态变量值在内存中,一个主要用应该就是模仿块级作用域,避免多人协作时变量命名冲突

最基本的闭包

			function fun(){
				var i = 0
				function son(){
					i++;
				}
				return son;
			}
			var closure = fun();

上面的例子就是典型的闭包当我们运行fun()()也就是运行son()的时候里面的变量i会因为原型链的原因会找到父级的i所以为0,并且当这里的son中的i发生改变fun中的i也会发生改变,但当全局变量中有一个变量i为1那么son中的i是不管全局中的i的因为他是一级一级的往上去找定义了i的区域,在父级这个地方找到了,就不会在往上找了,因此才会有了说:防止变量命名冲突\保存部分动态变量值在内存中,一个主要用应该就是模仿块级作用域,避免多人协作时变量命名冲突的作用

那我们来说一下闭包函数的一系列问题

1.都是引用什么时候相等什么时候不相等

首先我们要知道当我们var一个变量等于对象的时候知道时候,这个变量相当于这个对象的指针指向了这个对象,所以不管多少的变量等于这个对象他们这些对象都是想等的都是指向这个对象

		function fun(){
				var a = 1; 
				function fun2(){
					console.log(++a);
				}
				return fun2;
			}
		var aa = fun;
		var bb = fun;
		if (aa == bb){
			console.log("相同");
		}else{ 
			console.log("不想等");
		}//相等

注意这里是fun没有加括号,这里不可以有括号因为有了括号就是运行这个函数,吧return的值返回给了要赋值变量,那么问题来了当我们加上了括号的时候我们的aa和bb还想等吗?

我们先来个简单的例子

		function fun(){
				var a = 1; 
				function fun2(){
					console.log(++a);
				}
				return 2;
			}
		var aa = fun();
		console.log(aa); //2
		var bb = fun();
		console.log(bb); //2
		if (aa == bb){
			console.log("相同");
		}else{ 
			console.log("不想等");
		}//相等

这个时候为什么答案为相当因为这个时候aa和bb都是等于fun()运行后的return的结果为2为一个基本类型所以相当,看到这里肯定就有人知道下面的例子了,如果return一个引用类型还会想等吗?呵呵肯定不会那么为什么不会呢?好吧等下来看先看下例子

		function fun(){
				var a = 1; 
				function fun2(){
					console.log(++a);
				}
				return fun2;
			}
		var aa = fun();
		console.log(aa); //fun2(){}
		var bb = fun();
		console.log(bb); //fun2(){}
		if (aa == bb){
			console.log("相同");
		}else{ 
			console.log("不想等");
		}//不相等

那么在这个返回了一个引用类型(函数)的时候他们都为fun2(){},那么久有人想问了为什么他们都为fun2(){},但他们不相等,为什么呢?因为他是引用类型他和基本类型不用基本类型就是一个数字,相等就ok了,但是引用类型不用,他们判断是不是同一个不可以只单独看值是否想同,那么要怎么看呢?我们先来一个例子:如果有一个引用类型他们不单单值要想等他们在内存中的位置也要是一样的,比如var了a,b 等于fun那么a和b她们为什么相等应为他们指向了同一个函数,她们不单单值相同,而且位置相同(同一个所以位置相同),

所以我们这里例子中虽然fun2(){}的这个值是相同的但是他们不一样的原因是因为他们是两个值相同但是在不同位置,所以导致不一样的不同函数;那么有一个问题来了为什么我们都是返回的的fun2()他们的值会不在同一个地方(也就是说他们return了2次)

那么要解决这个问题我们先要了解一下我们的js机制中的处理内存的问题,简单来说也就是当对象例如函数当运行的时候会开辟内存空间,当运行完了这个函数的时候这个内存就会被释放,而闭包就结局了这个问题。

那么我们接上面的问题为什么不在同一个地方?因为每次执行这个函数的时候都是一个新的函数(都会产生一个新的执行期上下文),在加上他们返回的是一个引用类型所以每次返回的数据都是全新的,如果返回的是基本类型还是相同的

		function fun(){
				var a = 1; 
				function fun2(){
					console.log(++a);
				}
				return fun2;
			}
		var aa = fun();
		var bb = fun();
		aa();//2
		aa();//3
		aa();//4
		bb();//2
		bb();//3
		aa();//5

因为他们aa,bb他们返回的fun2都是值(逻辑)相同但是,位置不同的函数,所以他们每次运行是互不影响的,同时aa,bb他们有是自己一个独立的他们就会在运行了bb()后再运行aa()依旧会跟着上一次的值为5,

如果你们明白原型链,那么这里可以是这样说,因为当一个函数执行的前一刻,会创建一个执行期上下文(AO),执行期上下文会在函数执行完释放(一般情况下是),但是当闭包的时候,返回出来的函数还拿着父亲的AO,所以父亲的AO并没有释放,例如上面的例子aa,每次执行的时候都会有一个新的不相同的aa的AO,但是他们每次执行都是改变fun中的a的值就算aa()执行完了释放了,也不影响在他们父亲中的a的值,当var bb 的时候就有是另一个fun的A0了所以是重新开始的,

也就是说aa,bb就是在定义情况下的拿了属于他们的scope中包含了0--funAO 1---G0,他们是不相用的,这样执行的时候才会有属于他们的A0

好了大致的都写完了,来一写好玩的?如何取到闭包中的值

情况一:父级为函数声明

function fun(){
	var i = 1;
	function fun2(){
		return i;
	}
	return fun2;
}
	var a = fun()();
	console.log(a);//1

情况2:父级为匿名函数

先来个错误的示范

(function(){
	var i = 1;
	function fun2(){
		return i;
	}
	return fun2;
})()
console.log(fun2);//曝错因为这样是找不到fun2的虽然他是立即执行函数,但立即执行完了也就消失了,return的值fun2并没有被引用

确实是return了一个值,但是这个值并没有被引用,所以找不到了

正确的写法

var Arr = [];
(function(){
	var i = 1;
	Arr.push(i);
})()
console.log(Arr[0]);//1

或


var aa = (function(){
	var i = 1;
	function fun2(){
		return i;
	}
	return fun2;
})()
console.log(aa()); //1

把i的值传给了全局的数组的末尾(第key0)所以,输出Arr[0]就等于了i;

变量aa引用了匿名函数中return中的fun2函数,所以他aa执行的时候可以return中的i的值

在来一个例子

var Arr = [];
(function(){
	var zqx = "zqxzqx"
	console.log("zqx");
	aa();
	function aa(){
	    (function(){
			var a = 123;
			var b = 234;
			Arr.push(a);
			Arr.push(b);
			return a;
		})();
	}
	return aa;//这里是没有用的,因为这个aa对象还是在这个匿名的作用域没到全局中,除非有var一个变量来引用这个匿名函数的return中的值	
})();
//console.log(zqx);//未定义,虽然那个是自动执行的函数,但是他的作用域也不是全局,一样也是局部作用域
//console.log(aa);//未定义
  console.log(Arr[0]);
  console.log(Arr[1]);

好了,我目前对闭包的理解就是这样了,如果有什么地方写错了可以互相探讨呵呵,毕竟我我还是个小白呵呵

猜你喜欢

转载自blog.csdn.net/qq_39148344/article/details/85679389
今日推荐