日拱一卒:闭包及应用

56 阅读2分钟

最近面试几场,感慨不管有没有实际的业务经验,面试官还是会翻来覆去考察基础问题,这些问题看似简单,其实也需要比较深入的理解。

闭包

闭包效果:从内部函数访问外部函数的作用域

function A(){
    let a = 0
    function B() {
        a += 1
    }
    return B()
}

在A函数体内执行B函数

function A(){
    let a = 0
    return function() {
        a += 1
        return a
    }
}
const B = functionA() 
B()

闭包作用1:创建私有成员

从内部函数能访问外部函数的作用域,但是在外部函数之外无法直接访问,其实是创建了私有成员。既可以创建私有成员变量,又可以创建私有成员方法。

  • 不私有版本(Counter既能访问count属性,也能访问increment方法):
const makeCounter = function () {
  this.count = 0
  this.increment = function() {
      return this.count ++
  }
}
const Counter = new makeCounter()
Counter.count ++
  • 私有版本(变量的值和改方法都私有)
function createCounter() {
  let count = 0;
  function changeBy(val) {
    count += val;
  }
  return {
    increment: function () {
      changeBy(1);
    },
    decrement: function () {
      changeBy(-1);
    },
    value: function () {
      return counte;
    },
  };
};

var counter = createCounter()

Counter.increment();
console.log(Counter.value())

不论是上述的私有版本还是不私有版本,都可以进行状态保持,而不必使用全局变量

const Counter1 = new makeCounter()
const Counter2 = new makeCounter()
Counter1.increment()           
console.log(Counter1.count)    // 1
console.log(Counter2.count)    // 0
var counter1 = createCounter()
var counter2 = createCounter()
counter1.increment()
console.log(Counter1.count)    // 1
console.log(Counter2.count)    // 0

闭包作用2: 函数工厂--通过配置动态生成不同的函数,具有不同的行为和状态

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

这个例子也能说明,闭包能够对函数结果进行缓存,避免了重复运算。

闭包作用3:创建回调函数,将函数作为参数传给其它函数,并在适当时候执行

例如:防抖函数的实现。看下面例子。

闭包应用

防抖函数

function debounce(func, delay) {
    let timer
    return function() {
        if(timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(func,delay)
    }
}

const debounceFn = debounce(() => { console.log('1111') }, 300)

这样一来,每次调用deboounce函数的时候都可以根据配置生成新的回调函数,缓存了func和delay,在需要使用debounceFn回调函数时再使用。每次调用所生成的回调函数之间存在状态隔离,timer不会互相干扰;回调函数本身有状态保持,记录了timer的状态。