最近面试几场,感慨不管有没有实际的业务经验,面试官还是会翻来覆去考察基础问题,这些问题看似简单,其实也需要比较深入的理解。
闭包
闭包效果:从内部函数访问外部函数的作用域
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的状态。