JavaScript闭包的理解
1.闭包
-
闭包就是能够读取其他函数内部变量的函数,本质上就是一个函数,只不过是处于其他函数内部而已。
-
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域。
-
闭包的特性
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
2.闭包的理解
-
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念。
-
闭包 的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中。
-
闭包的另一个用处,是封装对象的私有属性和私有方法。
-
好处:
- 保护变量:闭包可以将变量封闭在函数内部,防止被外部访问和修改,实现数据的私有化。
- 延长变量的生命周期:外部函数执行完毕后,其内部函数仍然可以访问外部函数的变量,从而实现变量的长期保存。
- 实现模块化:通过闭包可以创建独立的模块,将相关的函数和数据封装在一起,提高代码的可维护性和复用性。
-
坏处:
- 内存泄漏:闭包会使得外部函数的变量一直保存在内存中,如果没有及时释放,可能会导致内存泄漏。
- 性能损耗:闭包会占用更多的内存空间,可能会导致性能下降,尤其是在循环中大量使用闭包时。
使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不应滥用闭包,否则可能会影响网页性能,并在IE中导致内存泄漏。
解决方法是,在退出函数之前,将不使用的局部变量全部删除
闭包的使用场景
1.封装私有变量和方法:
function createCounter() {
var count = 0; // 私有变量
function increment() { // 私有方法
count++;
console.log(count);
}
return increment; // 返回内部函数
}
var counter = createCounter();
counter(); // 输出 1
counter(); // 输出 2
2.实现函数柯里化:
function add(a) {
return function(b) {
return a + b;
};
}
var add5 = add(5);
console.log(add5(3)); // 输出 8
console.log(add5(7)); // 输出 12
3.事件处理:
function createButton() {
var count = 0;
var button = document.createElement('button');
button.textContent = 'Click me';
button.addEventListener('click', function() {
count++;
console.log('Button clicked ' + count + ' times');
});
return button;
}
var button = createButton();
document.body.appendChild(button);
4.防抖和节流
function debounce(func, delay) {
var timeoutId;
return function() {
var context = this;
var args = arguments;
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
func.apply(context, args);
}, delay);
};
}
function throttle(func, delay) {
var lastTime = 0;
return function() {
var context = this;
var args = arguments;
var currentTime = Date.now();
if (currentTime - lastTime >= delay) {
func.apply(context, args);
lastTime = currentTime;
}
};
}
5缓存:
function memoize(func) {
var cache = {};
return function() {
var args = JSON.stringify(arguments);
if (cache[args]) {
return cache[args];
}
var result = func.apply(this, arguments);
cache[args] = result;
return result;
};
}
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
var memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(10)); // 输出 55
console.log(memoizedFibonacci(10)); // 从缓存中获取结果,输出 55
总结
1.作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的
2.简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期