Day09 - 闭包应用1 - 制造惰性函数

简介: Day09 - 闭包应用1 - 制造惰性函数

📺 同步视频 一键三连


www.bilibili.com/video/BV1gr…


基本概念


惰性函数是函数是编程的一个重要概念。可以有效提高程序的运行效率。


惰性函数表示函数执行的分支只会在函数第一次调用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了。


如何实现计算缓存


假设有一个计算比如计算 平方,非常耗费时间。


需要把平方缓存起来,这样就不需要每次都计算了。


var cache = {}
function square(n) {
    if (!cache[n]) {
        cache[n] = n * n;
     }
     return cache[n];
}


使用闭包隐藏全局变量


以上代码虽然可以实现功能,但是最大的问题就是缓存需要定义一个全局变量。其实这个变量是可以隐藏的。


var square = (function () {
    var cache = {};
    return function(n) {
        if (!cache[n]) {
            cache[n] = n * n;
        }
        return cache[n];
    }
})();


惰性函数还能做什么


单例模式


单例模式是设计模式之一,它保证了一个类只有一个实例。实现方法一般是先判断实例是否存在,如果存在就直接返回,否则就创建了再返回。单例模式的好处就是避免了重复实例化带来的内存开销。


// 单例模式
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))
            }
        }
        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>


提高浏览器兼容问题的执行效率


为了解决浏览器之间的行为差异,经常会在代码中包含了大量的 if 语句,以检查浏览器特性,解决不同浏览器的兼容问题。


显然这些if语句我们只希望在一个浏览器中只执行一遍。


function addEvent(type, element, fun) {
  if (element.addEventListener) {
    element.addEventListener(type, fun, false);
  }
  else if (element.attachEvent) {
    element.attachEvent('on' + type, fun);
  }
  else {
    element['on' + type] = fun;
  }
}


最佳的办法就是使用惰性函数将结果缓存起来。


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);
}


第一次执行: 选择合适的api并且执行


第二次执行: 由于addEvent已经被指定为其中的一种


最后我们再看看ajax兼容性的代码


没有惰性


function createXHR(){
  var xhr = null;
  try {
    // Firefox, Opera 8.0+, Safari,IE7+
    xhr = new XMLHttpRequest();
  }
  catch (e) {
    // Internet Explorer 
    try {
      xhr = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
      try {
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {
        xhr = null;
      }
    }
  }
  return xhr;
}


惰性


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;
}


面试攻略



点评


  • 闭闭包处处都有,但是能说出经典应用又是一个难题。说Helloworld和背题没啥区别。


相关文章
什么是闭包,闭包的特性
什么是闭包,闭包的特性
124 0
|
4月前
|
存储 JavaScript 前端开发
块级作用域和函数作用域的区别在哪些方面会对性能产生影响?
【10月更文挑战第29天】块级作用域和函数作用域在变量查找效率、内存管理、闭包、代码执行顺序以及作用域链维护等方面的区别,都会在不同程度上对性能产生影响。在实际开发中,需要根据具体的代码逻辑、应用场景和性能需求,合理地选择和运用这两种作用域,以达到最佳的性能和代码质量平衡。
|
9月前
|
存储 JavaScript 前端开发
技术经验解读:什么是闭包?闭包的优缺点?
技术经验解读:什么是闭包?闭包的优缺点?
138 1
|
10月前
|
存储 缓存 自然语言处理
高阶函数离不开闭包
高阶函数离不开闭包
|
存储 关系型数据库 Python
函数式编程:一等对象、作用域和高阶函数的综合指南
函数式编程:一等对象、作用域和高阶函数的综合指南
68 0
|
JavaScript 前端开发
|
前端开发 JavaScript
都2020年了,你还不懂什么是闭包吗---深入理解闭包这一篇文章足以
都2020年了,你还不懂什么是闭包吗---深入理解闭包这一篇文章足以
103 0
什么是闭包?闭包的用途是什么?闭包的缺点是什么?
变量的作用域有两种:全局变量和局部变量; 函数内部可以直接读取全局变量; 在函数外部无法读取函数内的局部变量。 能够读取其他函数内部变量的函数,就是闭包
138 0
|
自然语言处理 JavaScript 前端开发
每日一题:说说你对闭包的理解?闭包使用场景
每日一题:说说你对闭包的理解?闭包使用场景
132 0
|
自然语言处理 JavaScript 前端开发
Day08 - 什么是闭包?如何制造闭包?
Day08 - 什么是闭包?如何制造闭包?
147 0