前端学习:闭包及其应用

本文章整理闭包相关知识,包括闭包的介绍及原理、闭包的优缺点、闭包的应用。

什么是闭包?

闭包就是函数中的局部变量(作用域在父级函数)被函数中的嵌套函数所使用,就会形成一个闭包。
原理是父级作用域的变量可以被子作用域所使用。

如何使用闭包?为什么要使用闭包?

  • 我们可以把这个嵌套函数return出去,这样函数外部就能够间接的访问到这个局部变量了。
  • 我们给return出去的函数设定一些规定的操作,这样外部调用时,就只能按照我们规定的方法来间接访问该局部变量。这样可以保护这个变量不被随意修改。
  • 闭包的用途:
    (1)可以读取函数内部的变量;
    (2)让这些变量的值始终保持在内存中。

闭包的应用

单例模式:

保证一个类只能创建一个对象,并提供一个全局访问点。
实现方式:先判断对象是否存在,存在则直接return,不存在则创建新对象。

//单例模式
var createHtml = function(html){
	this.html = html;
}

var Singleton = (function(){
	let instance;
	return function(html){
		if(!instance){
			instance = new createHtml(html);
		}
		return instance;
	}
})();//自执行

//测试
var instance1 = new Singleton('section1');
var instance2 = new Singleton('section2');
console.log(instance1);//createHtml { html: 'section1' }
console.log(instance2);//createHtml { html: 'section1' }
console.log(instance1 === instance2);//true

【经典】读取函数内部的变量、外部间接访问变量、变量始终保存在内存中:

//闭包
function getHeight(){
	let height = 0;//外界无法直接访问到height,初始值为0
	function plus(){
		//嵌套函数可以访问到height(父对子透明)
		height = height + 1;
	}
	function getH(){
		//嵌套函数可以访问到height(父对子透明)
		console.log('height:' + height);
		return height;
	}
	function double(){
		height = height * height;
	}
	function clearH(){//该方法将闭包内部的变量设置为null, 让变量失去引用,会被系统自动回收。
		height = null;
	}
	//将方法return出去来让外部可以对height进行间接的访问
	return {
		plus:plus,
		getH:getH,
		double:double,
		clearH:clearH
	}
}
//测试
var result = getHeight();
result.getH();//height:0
result.plus();//height+1
result.plus();//height+1
result.getH();//height:2
result.double();
result.getH();//height:4,说明height没有被垃圾回收机制回收,因为其他嵌套函数比如getH()依赖于getHeight父函数,子函数被赋予了一个全局变量,因此匿名函数在内存中,而该匿名函数又依赖于父函数,因此父函数getHeight也在内存中
//console.log(height);//error
result.clearH();//让变量失去引用,会被系统自动回收,也可以直接result=null,来删除整个闭包。
result.getH();//height:null,清除了闭包中的变量
result = getHeight();
result.getH();//height:0,说明上面清除成功

扩展:垃圾回收机制

闭包的缺点(注意点)

  • this的指向:闭包函数是在window作用域下执行的,也就是说,this指向windows。
  • 内存消耗与泄漏问题:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  • 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

参考:

[1]阮一峰的网络日志——学习Javascript闭包(Closure)

[2]什么是闭包?闭包的优缺点?

[3]Web开发技术/Javascript/内存管理

你可能感兴趣的:(前端学习,javascript)