思维导图
一、什么是闭包机制
函数执行形成的私有上下文,即能保护里面的私有变量不受外界干扰,也能在当前上下文中保存一些信息(前提:形成的上下文不销毁),上下文中的这种保存和保护机制,就是闭包机制
二、闭包的两大作用
1、保护作用
在这个上下文中会有一些私有的变量AO(XX),这些私有的变量和外界的变量不会冲突(互不影响)
2、保存作用
某些情况下,上下文中的某些内容被外界占用后,当前上下文并不会出栈销毁,这样就会把上下文中的一些信息储存起来
三、闭包的应用
1.利用闭包的保护作用
-1).团队协作开发中;
A/B
共同开发一个页面,最后要把代码合并在一起,为了防止全局变量的冲突污染,我们建议每个开发者,都把自己的代码放置到一个闭包中(自执行函数执行即可,这样就是私有的上下文)保护起来
// A的代码
(function anonymous() {
/* 自执行函数执行,会形成一个私有的上下文,在这里声明+定义的变量或者函数都是私有的 */
var x = 100,
y = 200;
function func() {
// ...
}
})();
// B的代码
~ function anonymous() {
// console.log(anonymous); //=>函数本身
//=>匿名函数设置的函数名只能在函数里面应用,函数外面是无法访问的
var x = 200,
n = 0;
function func() {
// ...
}
function handled() {
// ...
}
}();
// console.log(anonymous); //=>Uncaught ReferenceError: anonymous is not defined
复制代码
-2).封装一个插件或者类库等;
- 为了防止我们定义的变量和方法 和 用户定义的冲突,我们也是需要把所有写的代码放到一个闭包中,例如:
jQuery
…
- 为了防止我们定义的变量和方法 和 用户定义的冲突,我们也是需要把所有写的代码放到一个闭包中,例如:
/* JQUERY源码一瞥 */
// typeof window !== "undefined" ? window : this 浏览器端window是存在的,所以为window
(function (global, factory) {
"use strict";
// => global===window
// => factory===function (window, noGlobal){...}
factory(global);
})(window, function (window, noGlobal) {
// JQUERY的源码
});
//=> 利用闭包的机制,把JQ源码当作自执行函数的形参传给函数,完成执行
复制代码
2.利用闭包的保存作用
- -1).在某些需求中,我们经常需要形成一个闭包,存储一些值(而且不能销毁),这样来供后面的程序运行使用(例如:惰性函数、柯理化函数、compose函数等JS高阶编程技巧中,就是基于闭包的保存机制实现的)
此时我们发现一个问题:每个人的代码都独立了,那我们每个人都会用到的公共方法,难道也要都单独写一遍?
有此需求,必然得有解决办法:
四、闭包内的值暴露给外面使用的两种方法
需求:我们需要把某一个闭包(私有上下文)中的值暴露到外面
1、基于window.xxx=xxx暴露到全局
这种办法虽然可以实现,但是也会存在冲突,如果我们每一个版块都需要暴露更多的方法,同时都基于这种方法暴露到全局对象GO上,也可能导致方法之间的冲突
(function anonymous() {
function queryURLParams() {
// ...
}
function sum() {
// ...
}
// 想暴露到外面使用,可以暴露到全局上(赋值给全局对象GO =>window)
window.queryURLParams = queryURLParams;
window.sum = sum;
})();
queryURLParams(); //=>window.queryURLParams()
复制代码
2、JS中的设计模式:单例设计模式
每一个版块暴露到全局下只有一个变量而已,所有需要供别人调取的方法都在对象中(这样暴露一个或者多个都无所谓)
- 避免了全局变量的污染,也同时实现了不同闭包之间方法的公用性
var utils = (function anonymous() {
// queryURLParams:获取URL地址参数信息
function queryURLParams() {
// ...
}
// sum:实现任意数求和
function sum() {
// ...
}
// 把需要供外面访问的变量和方法,赋值给一个对象,最后返回(外层基于VAR utils定义变量来接收即可)
return {
queryURLParams: queryURLParams,
sum: sum
}; //=>return AAAFFF000;
})();
// console.log(utils); //=>{queryURLParams:函数,sum:函数}
utils.queryURLParams();
utils.sum();
复制代码
utils对象中包含了需要供别人调取使用的方法;此时我们把utils称之为“命名空间”,而对象就是一个空间,空间中包含了当前版块中的内容,或者是把当前版块中的内容按照命名空间进行了分组,每一个分组都是一个单独的个体
命名空间
- 把每一个对象值 赋值给变量 =>可以理解为,给每一个对象的堆内存空间起了个变量名,所以此时可以把这个变量称为 “命名空间”
- 当前对象中的键值对都是 命名空间 中私有的键值对
五、闭包的优缺点
1、优点
- 上述我们一直说的保护和保存作用
2、缺点
- 因为闭包会产生不销毁的上下文,这样导致栈/堆内存消耗过大,有时候也会导致内存泄漏等,影响页面的运行性能,所以在真实项目中,要合理应用闭包(不要滥用)