快捷搜索:  汽车  科技

闭包的使用场景有(闭包一)

闭包的使用场景有(闭包一)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只暴露 $ 就好了循环内加入即时函数,由于即时函数的参数为实参复制关系,相当于复制的现场快照<script src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js"></script> <script> // 假设其他库占用的$ const $ = () =>

应用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 复制代码 复制代码

闭包的使用场景有(闭包一)(1)

  • 整体使用自运行函数 - 任何变量不污染全局
  • 变量 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

猜您喜欢: