闭包(一):闭包的9个应用场景
csdh11 2024-12-02 16:38 25 浏览
应用1:创建临时独立作用域
假设想创建一个累加器这样的功能,需要一个临时变量用于保存累加状态。放在全局作用域显然不太优雅,最简单的方法就是创建一个IIFE(立即执行函数)然后创建变量,返回一个函数,然后再函数中完成累加功能。
// 以前
var n= 0
setInterval(() => console.log(++n), 1000)
复制代码
// 现在
setInterval((function() {
var n = 0
return function() {
console.log(++n)
}
})(), 1000)
复制代码
应用2:解决变量名冲突
利用参数优先全局变量的规则,可以让函数内部的小环境内限制作用域变量名称。
比如: jquery会使用全局的,但是其他库也有可能使用, 但是其他库也有可能使用,但是其他库也有可能使用这个函数名,这样就会造成函数名冲突。
假定我们有大量存量代码使用$这个函数名调用jquery,我们不太可能全部改写这个代码。这时候其实使用即时函数就可以很好的解决这个问题。
<script src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js"></script>
<script>
// 假设其他库占用的$
const $ = () => console.log("Not jQuery");
// 闭包限制当前作用域的$
(function ($) {
$(document).ready(function () {
console.log("Hello jQuery");
});
})(jQuery);
$()
</script>
复制代码
应用3:使用简洁变量名
第三个场景类似with这个功能
// with主要是用来对对象取值的(复杂结构with影响性能),如下所示:
with(obj) {
var newa = a;
var newb = b;
console.log(newa+newb);
}
该语句 等价于:
var newa = obj.a;
var newb = obj.b;
console.log(newa+newb);
复制代码
// 一个复杂的变量
var data {
abc : {
efg : 0
}
}
(function() {
console.log(v)
})(data.abc.efg)
复制代码
现在有了解构赋值,这一个场景作用不大了。
应用4:循环陷阱
作为Javascript面试题八大陷阱题之一,我们下面看看循环陷阱是如何解决的。
循环内加入即时函数,由于即时函数的参数为实参复制关系,相当于复制的现场快照
const ary = [];
for (var i = 0; i < 5; i++) {
(function(n) {·
ary.push(function () {
return console.log(n);
});
})(i)
}
ary[0]();
ary[1]();
复制代码
应用5:类库封装
类库封装最重要的要求就是不能让类库中的变量污染全局。 比如jQuery只暴露 $ 就好了
封装1:
(function () {
var jQuery = window.$ = function() {
// initialize
}
})()
复制代码
- jQuery构造器(匿名函数)赋值给window.$ 作为全局变量
- 为了保证其他代码改变或删除jQuery变量 , 所以声明一个局部变量jQuery, 保证jQuery代码内都可以使用jQuery这个名字。
封装2:
var $ = (
function() {
function jQuery() { // Initialize }
return jQuery
}
)()
复制代码
应用6:webpack打包模块
A模块 a.js
// a.js
const time = Date.now()
module.exports = 'A:' + time
复制代码
复制代码
入口index.js
// index.js
const a = require("./a");
console.log(a);
复制代码
复制代码
运行webpack打包
npx webpack
复制代码
复制代码
- 整体使用自运行函数 - 任何变量不污染全局
- 变量 o 为模块集合
var o = {
// 原来的a.js
85: (o) => {
const r = Date.now();
o.exports = "A:" + r;
},
},
复制代码
- t函数为exports、require模拟函数
- r = {}; // 模拟exports对象 function t(e) { // 模拟require函数 var n = r[e]; if (void 0 !== n) return n.exports; var s = (r[e] = { exports: {} }); return o[e](s, s.exports, t), s.exports; } 复制代码
- 入口为自执行函数 引用o 、t变量形成闭包
- (() => { const o = t(85); console.log(o); })(); 复制代码 复制代码
- 由于t函数是变量提升的所以require函数也可以在子模块里调用 - 这个大家可以自己实验一下。
应用7:惰性函数
惰性函数表示函数执行的分支只会在函数第一次调用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了。
7.1 实现计算缓存
var square = (function (){
// 注意cache限制大小
var cache = {}
return function(n){
return (cache[n] = n * n)
}
})()
复制代码
7.2 单例模式缓存
实现方法一般是先判断实例是否存在,如果存在就直接返回,否则就创建了再返回。单例模式的好处就是避免了重复实例化带来的内存开销。 就是避免了重复实例化带来的内存开销。
// 单例模式
function Singleton(){
this.data = 'singleton';
}
Singleton.getInstance = (function () {
var instance;
return function(){
if (instance) {
return instance;
} else {
// 缓存实例
instance = new Singleton();
return instance;
}
}
})();
var sa = Singleton.getInstance();
var sb = Singleton.getInstance();
console.log(sa === sb); // true
console.log(sa.data); // 'singleton'
复制代码
单例模式前端最典型的应用场景,全局唯一消息框。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.model {
width: 200px;
height: 200px;
border: 1px solid aqua;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
</style>
</head>
?
<body>
<div id="loginBtn">点我</div>
<script>
// 惰性函数
var getSingle = function (fn) {
var result;
return function () {
//没有缓存
return result || (result = fn.apply(this, arguments))
}
}
// 创建dom对象
var createLoginLayer = function () {
var oDiv = document.createElement("div");
oDiv.innerHTML = "我是登录浮窗";
oDiv.className = "model";
oDiv.style.display = "none";
document.body.appendChild(oDiv);
return oDiv;
}
var createSingleLoginLayer = getSingle(createLoginLayer);
document.getElementById("loginBtn").onclick = function () {
//动态创建弹窗
//新建一个弹窗实例,内部使用单例模式管理,一直只能有一个.
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = "block"
}
</script>
</body>
复制代码
7.3 提高浏览器兼容问题的执行效率
bom api兼容
function addEvent(type, element, fun) {
if (element.addEventListener) {
addEvent = function (type, element, fun) {
element.addEventListener(type, fun, false);
}
}
else if (element.attachEvent) {
addEvent = function (type, element, fun) {
element.attachEvent('on' + type, fun);
}
}
else {
addEvent = function (type, element, fun) {
element['on' + type] = fun;
}
}
return addEvent(type, element, fun);
}
复制代码
ajax兼容
function createXHR() {
var xhr = null;
if (typeof XMLHttpRequest != "undefined") {
xhr = new XMLHttpRequest();
createXHR = function () {
return new XMLHttpRequest();
};
} else {
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
createXHR = function () {
return new ActiveXObject("Msxml2.XMLHTTP");
};
} catch (e) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
createXHR = function () {
return new ActiveXObject("Microsoft.XMLHTTP");
};
} catch (e) {
createXHR = function () {
return null;
};
}
}
}
return xhr;
}
复制代码
应用8:函数颗粒化
应用9:hooks
- 上一篇:判断变量是否为数组
- 下一篇:Java基础—Document类型的变化
相关推荐
- SpringBoot+LayUI后台管理系统开发脚手架
-
源码获取方式:关注,转发之后私信回复【源码】即可免费获取到!项目简介本项目本着避免重复造轮子的原则,建立一套快速开发JavaWEB项目(springboot-mini),能满足大部分后台管理系统基础开...
- Spring Boot+Vue全栈开发实战,中文版高清PDF资源
-
SpringBoot+Vue全栈开发实战,中文高清PDF资源,需要的可以私我:)SpringBoot致力于简化开发配置并为企业级开发提供一系列非业务性功能,而Vue则采用数据驱动视图的方式将程序...
- 2021年超详细的java学习路线总结—纯干货分享
-
本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础...
- 探秘Spring Cache:让Java应用飞起来的秘密武器
-
探秘SpringCache:让Java应用飞起来的秘密武器在当今快节奏的软件开发环境中,性能优化显得尤为重要。SpringCache作为Spring框架的一部分,为我们提供了强大的缓存管理能力,让...
- 3,从零开始搭建SSHM开发框架(集成Spring MVC)
-
目录本专题博客已共享在(这个可能会更新的稍微一些)https://code.csdn.net/yangwei19680827/maven_sshm_blog...
- Spring Boot中如何使用缓存?超简单
-
SpringBoot中的缓存可以减少从数据库重复获取数据或执行昂贵计算的需要,从而显著提高应用程序的性能。SpringBoot提供了与各种缓存提供程序的集成,您可以在应用程序中轻松配置和使用缓...
- 我敢保证,全网没有再比这更详细的Java知识点总结了,送你啊
-
接下来你看到的将是全网最详细的Java知识点总结,全文分为三大部分:Java基础、Java框架、Java+云数据小编将为大家仔细讲解每大部分里面的详细知识点,别眨眼,从小白到大佬、零基础到精通,你绝...
- 1,从零开始搭建SSHM开发框架(环境准备)
-
目录本专题博客已共享在https://code.csdn.net/yangwei19680827/maven_sshm_blog1,从零开始搭建SSHM开发框架(环境准备)...
- 做一个适合二次开发的低代码平台,把程序员从curd中解脱出来-1
-
干程序员也有好长时间了,大多数时间都是在做curd。现在想做一个通用的curd平台直接将我们解放出来;把核心放在业务处理中。用过代码生成器,在数据表设计好之后使用它就可以生成需要的controller...
- 设计一个高性能Java Web框架(java做网站的框架)
-
设计一个高性能JavaWeb框架在当今互联网高速发展的时代,构建高性能的JavaWeb框架对于提升用户体验至关重要。本文将从多个角度探讨如何设计这样一个框架,让我们一起进入这段充满挑战和乐趣的旅程...
- 【推荐】强&牛!一款开源免费的功能强大的代码生成器系统!
-
今天,给大家推荐一个代码生成器系统项目,这个项目目前收获了5.3KStar,个人觉得不错,值得拿出来和大家分享下。这是我目前见过最好的代码生成器系统项目。功能完整,代码结构清晰。...
- Java面试题及答案总结(2025版持续更新)
-
大家好,我是Java面试分享最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试场景题及答案。...
- Java开发网站架构演变过程-从单体应用到微服务架构详解
-
Java开发网站架构演变过程,到目前为止,大致分为5个阶段,分别为单体架构、集群架构、分布式架构、SOA架构和微服务架构。下面玄武老师来给大家详细介绍下这5种架构模式的发展背景、各自优缺点以及涉及到的...
- 本地缓存GuavaCache(一)(guava本地缓存原理)
-
在并发量、吞吐量越来越大的情况下往往是离不开缓存的,使用缓存能减轻数据库的压力,临时存储数据。根据不同的场景选择不同的缓存,分布式缓存有Redis,Memcached、Tair、EVCache、Aer...
- 一周热门
- 最近发表
- 标签列表
-
- mydisktest_v298 (34)
- document.appendchild (35)
- 头像打包下载 (61)
- acmecadconverter_8.52绿色版 (39)
- word文档批量处理大师破解版 (36)
- server2016安装密钥 (33)
- mysql 昨天的日期 (37)
- parsevideo (33)
- 个人网站源码 (37)
- centos7.4下载 (33)
- mysql 查询今天的数据 (34)
- intouch2014r2sp1永久授权 (36)
- 先锋影音源资2019 (35)
- jdk1.8.0_191下载 (33)
- axure9注册码 (33)
- pts/1 (33)
- spire.pdf 破解版 (35)
- shiro jwt (35)
- sklearn中文手册pdf (35)
- itextsharp使用手册 (33)
- 凯立德2012夏季版懒人包 (34)
- 冒险岛代码查询器 (34)
- 128*128png图片 (34)
- jdk1.8.0_131下载 (34)
- dos 删除目录下所有子目录及文件 (36)