JavaScript闭包(Closures)

什么是闭包?

概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域。

简言之,闭包 =  内层函数 + 被函数引用的外部变量 

通常会使用一个函数包裹闭包结构,起一个变量保护作用

闭包的作用是使变量私有化,防止外部调用、修改

return:当需要对闭包内的变量进行调用,可以使用return,但仍不可修改

闭包可能会造成内存泄漏的问题

function fn(){
    let count = 1
    function fun(){
        count++
        console.log("函数被调用了${count}次")  
    }
    return fun
}
const result = fn()
result()
result()

在这一段代码中,我们定义了一个全局变量result,全局变量使用后不会被销毁,result调用fn函数,fn函数使用fun函数,fun函数使用count,所以count变量就会一直存在不会被销毁,就造成了内存泄漏的问题。

什么是内存泄漏?

在JavaScript中,内存泄漏是指程序分配的内存由于某种原因没有被正确释放,导致这些不再需要的内存无法被回收,从而占用系统资源,最终可能导致程序性能下降甚至崩溃。内存泄漏通常发生在不再使用的对象或数据仍然被引用时,导致垃圾回收器无法将其清除。

1.意外的全局变量:如果变量声明时漏掉了 varletconst,它会被意外地创建为全局变量,并且一直存在于全局作用域中。

function foo() {
  bar = 'This is a global variable'; // 应该使用 let 或 var 声明
}

2.闭包:闭包使内部函数可以访问外部函数的变量,但如果没有正确管理,闭包会导致不必要的变量保持引用,无法被垃圾回收。

function outer() {
  let obj = { name: 'memory leak' };
  return function inner() {
    console.log(obj);
  };
}
let leak = outer();

3.被遗忘的定时器或回调:当 setIntervalsetTimeout 没有被清除时,函数仍然在内存中保留引用,导致内存泄漏。

let timer = setInterval(() => {
  console.log('This will leak memory if not cleared');
}, 1000);

// 没有使用 clearInterval(timer) 来清除定时器

4.DOM 引用未被清理:当一个 DOM 元素(比如一个按钮或图片)被从页面中删除时,通常它会被浏览器的垃圾回收机制处理,释放其占用的内存资源。然而,如果 JavaScript 代码中仍然有对这个元素的引用,比如保存在变量里,那么即便该元素已经从页面中删除了,内存也无法被释放。这会导致内存泄漏,因为垃圾回收机制认为该对象仍然被使用。

let element = document.getElementById('myElement'); // 获取 DOM 元素
document.body.removeChild(element); // 从页面中移除该元素

// 尽管从页面中移除了,但 element 变量仍然引用着该 DOM 对象

在这种情况下,即使该元素从页面上消失了,但因为 element 变量仍然持有这个 DOM 节点的引用,它的内存就不会被回收。如果有很多类似的引用未被清理,内存消耗会逐渐增加。

为了避免这种问题,我们可以在删除 DOM 元素后,手动清理对它的引用:

let element = document.getElementById('myElement');
document.body.removeChild(element);
element = null; // 手动解除引用,允许垃圾回收器回收内存

5.事件监听器未被移除:当给 DOM 元素绑定了事件监听器(如点击事件),如果该元素被删除但事件监听器没有被移除,浏览器仍然会在内存中保留这个事件监听器的引用,导致该元素无法被完全释放。这也是一种常见的内存泄漏场景。

let button = document.getElementById('myButton');
button.addEventListener('click', () => {
  console.log('Button clicked!');
});

// 后来这个按钮被移除了,但监听器没有移除
document.body.removeChild(button);

即使按钮被删除了,JavaScript 依然记得它的事件监听器,这意味着与按钮相关的内存仍然被占用。

在删除 DOM 元素之前,应该手动移除所有绑定的事件监听器:

let button = document.getElementById('myButton');
let handleClick = () => {
  console.log('Button clicked!');
};

button.addEventListener('click', handleClick);

// 在删除按钮之前,先移除事件监听器
button.removeEventListener('click', handleClick);
document.body.removeChild(button);

预防内存泄漏的措施

  • 避免使用未声明的全局变量。
  • 使用 clearIntervalclearTimeout 清除不再需要的定时器。
  • 确保在不再需要时手动移除事件监听器。
  • 小心处理闭包,确保没有不必要的引用。
  • 定期检查程序中是否有无用的引用,可以使用浏览器的开发者工具监控内存使用情况

什么是DOM?

概念:DOM(文档对象模型,Document Object Model)是一个跨平台、语言中立的接口,它将 HTML、XML 文档结构化表示为一个树形结构。通过 DOM,程序可以动态地访问和操作文档的内容、结构以及样式。它允许 JavaScript 等编程语言与网页进行交互,改变页面元素、属性、事件等。

DOM 就像是网页的“地图”或“骨架”,它将网页的所有元素(如按钮、文本、图片)组织成一棵树。这棵树上每一个元素都是一个“节点”,开发者可以通过 JavaScript 去找到这些节点,然后对它们做各种操作,比如修改文本内容、添加新的元素或删除不需要的部分。DOM 让网页变得“活起来”,使得我们可以通过代码动态修改网页。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值