闭包理解和防抖/节流

闭包

  闭包是(函数)和(声明该函数的词法环境)的组合。

例子

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用,而 displayName实例仍可访问其词法作用域中的变量,即可以访问到 name 。由此,当 myFunc 被调用时,name 仍可被访问,其值 Mozilla 就被传递到alert中。

例子

function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

我们定义了 makeAdder(x) 函数,它接受一个参数 x ,并返回一个新的函数。返回的函数接受一个参数 y,并返回x+y的值。

从本质上讲,makeAdder 是一个函数工厂 — 他创建了将指定的值和它的参数相加求和的函数。在上面的示例中,我们使用函数工厂创建了两个新函数 — 一个将其参数和 5 求和,另一个和 10 求和。

add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。

模拟私有方法

我们可以使用闭包来模拟私有方法。私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱了代码的公共接口部分。

下面的示例展现了如何使用闭包来定义公共函数,并令其可以访问私有函数和变量。这个方式也称为 模块模式(module pattern):

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();

console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */

我们只创建了一个词法环境,为三个函数所共享:Counter.increment,Counter.decrement 和 Counter.value

MDN打不开了,公司的网络666

近期遇到的面试题:闭包的优点和缺点。当时就回了句不清楚,早前也接触过知道一些,但是并不能用语言表示出来。

优点:闭包环境可以定义私有变量。

缺点:在闭包内var声明的变量不能自动释放。

解决方法:将声明的变量写成构造器或是使用对象字面量的方式书写,这个主要是为了改变函数内this指向,使delete能成功。(看到觉得理解不对的请指出!!!!!)

常用的方法:节流,防抖

// 最后一次操作延时wait执行函数
      const debounce = (func, wait = 3000) => {
        let timer = null;
        return (...arguments) => {
          if (timer) clearTimeout(timer);
          timer = setTimeout(() => {
            func.apply(this, arguments);
            clearTimeout(timer);
          }, wait);
        };
      };

      let func = debounce(logThis);
      //
      const throttle = (func, wait = 3000) => {
        let curTime = new Date().getTime();
        let run = false;
        return (...arguments) => {
          if (run === false) {
            run = true;
            func.apply(this, arguments);
          }
          let nowTime = new Date().getTime();
          if (nowTime - curTime >= wait) {
            func.apply(this, arguments);
            curTime = nowTime;
          }
        };
      };
      let func2 = throttle(logThis);

调用:

<button onclick="func(1,2)">debounce</button>
<button onclick="func2(1,2)">func2</button>

 

 

 

  

posted @ 2018-08-07 11:30  Merrys  阅读(242)  评论(0编辑  收藏  举报