2024-12-17 日报 Day38

2024-12-17 日报 Day38

Yuyang 前端小白🥬

今日的鸡汤

你今天的一言一行,都是在为以后的成功谋篇布局。

今日学习内容

1、JS红皮书P99-102 第四章:变量、作用域与内存

今日笔记

1、内存泄露:在内存有限的设备上,或者在函数会被调用很多次的情况下,内存泄漏可能是个大问题。JavaScript 中的内存泄漏大部分是由不合理的引用导致的。
意外声明全局变量是最常见但也最容易修复的内存泄漏问题。
定时器也会导致内存泄露。下面的代码中,定时器的回调通过闭包引用了外部变量:

1
2
3
4
let name = 'Jake'; 
setInterval(() => {
console.log(name);
}, 100);

只要定时器一直运行,回调函数中引用的 name 就会一直占用内存。垃圾回收程序当然知道这一点,因而就不会清理外部变量。
使用 JavaScript 闭包很容易在不知不觉间造成内存泄漏。请看下面的例子:

1
2
3
4
5
6
let outer = function() { 
let name = 'Jake';
return function() {
return name;
};
};

2、静态分配与对象池:为了提升 JavaScript 性能,最后要考虑的一点往往就是压榨浏览器了。此时,一个关键问题就是如何减少浏览器执行垃圾回收的次数。开发者无法直接控制什么时候开始收集垃圾,但可以间接控制触发垃圾回收的条件。理论上,如果能够合理使用分配的内存,同时避免多余的垃圾回收,那就可以保住因释放内存而损失的性能。
一个策略是使用对象池。在初始化的某一时刻,可以创建一个对象池,用来管理一组可回收的对象。应用程序可以向这个对象池请求一个对象、设置其属性、使用它,然后在操作完成后再把它还给对象池。由于没发生对象初始化,垃圾回收探测就不会发现有对象更替,因此垃圾回收程序就不会那么频繁地运
行。下面是一个对象池的伪实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// vectorPool 是已有的对象池 
let v1 = vectorPool.allocate();
let v2 = vectorPool.allocate();
let v3 = vectorPool.allocate();
v1.x = 10;
v1.y = 5;
v2.x = -3;
v2.y = -6;
addVector(v1, v2, v3);
console.log([v3.x, v3.y]); // [7, -1]
vectorPool.free(v1);
vectorPool.free(v2);
vectorPool.free(v3);
// 如果对象有属性引用了其他对象
// 则这里也需要把这些属性设置为 null
v1 = null;
v2 = null;
v3 = null;

3、小结: JavaScript 变量可以保存两种类型的值:原始值和引用值。原始值可能是以下 6 种原始数据类型之一:Undefined、Null、Boolean、Number、String 和 Symbol。原始值和引用值有以下特点。
 原始值大小固定,因此保存在栈内存上。
 从一个变量到另一个变量复制原始值会创建该值的第二个副本。
 引用值是对象,存储在堆内存上。
 包含引用值的变量实际上只包含指向相应对象的一个指针,而不是对象本身。
 从一个变量到另一个变量复制引用值只会复制指针,因此结果是两个变量都指向同一个对象。
 typeof 操作符可以确定值的原始类型,而 instanceof 操作符用于确保值的引用类型。
任何变量(不管包含的是原始值还是引用值)都存在于某个执行上下文中(也称为作用域)。这个上下文(作用域)决定了变量的生命周期,以及它们可以访问代码的哪些部分。执行上下文可以总结如下。
 执行上下文分全局上下文、函数上下文和块级上下文。
 代码执行流每进入一个新上下文,都会创建一个作用域链,用于搜索变量和函数。
 函数或块的局部上下文不仅可以访问自己作用域内的变量,而且也可以访问任何包含上下文乃至全局上下文中的变量。
 全局上下文只能访问全局上下文中的变量和函数,不能直接访问局部上下文中的任何数据。
 变量的执行上下文用于确定什么时候释放内存。
JavaScript 是使用垃圾回收的编程语言,开发者不需要操心内存分配和回收。JavaScript 的垃圾回收程序可以总结如下。
 离开作用域的值会被自动标记为可回收,然后在垃圾回收期间被删除。
 主流的垃圾回收算法是标记清理,即先给当前不使用的值加上标记,再回来回收它们的内存。
 引用计数是另一种垃圾回收策略,需要记录值被引用了多少次。JavaScript 引擎不再使用这种算法,但某些旧版本的 IE 仍然会受这种算法的影响,原因是 JavaScript 会访问非原生 JavaScript 对象(如 DOM 元素)。
 引用计数在代码中存在循环引用时会出现问题。
 解除变量的引用不仅可以消除循环引用,而且对垃圾回收也有帮助。为促进内存回收,全局对象、全局对象的属性和循环引用都应该在不需要时解除引用。

此页目录
2024-12-17 日报 Day38