一、垃圾回收
垃圾回收程序会周期性运行,如果内存中分配了很多变量,则可能造成性能损失,因此垃圾回收的时间调度很重要。尤其是在内存有限的移动设备上,垃圾回收有可能会明显拖慢渲染的速度和帧速率。开发者不知道什么时候运行时会收集垃圾,因此最好的办法是在写代码时就要做到:无论什么时候开始收集垃圾,都能让它尽快结束工作。
二、内存管理
将内存占用量保持在一个较小的值可以让页面性能更好。优化内存占用的最佳手段就是保证在执行代码时只保存必要的数据。如果数据不再必要,那么把它设置为 null,从而释放其引用。这也可以叫作解除引用。这个建议最适合全局变量和全局对象的属性。局部变量在超出作用域后会被自动解除引用,如下面的例子所示:
function xingneng1(name){
let a = new Object();
a.name= name;
return a ;
}
let b = xingneng1("Rose")
// 接触 b 对值的引用
b = null;
在上面的代码中,b 保存着 xingneng1()函数调用返回的值。在xingneng1内部,a 创建了一个对象并给他添加了一个name 属性,然后 a 作为函数被返回,并被赋值给 b 。a在xingneng1()执行完成超出上下文后会自动被接触引用,不需要显示处理。但b是一个全局变量,最后一行,在不需要时b时手动解除引用。
注意:解除对一个值的引用不会自动导致相关内存被回收。接触引用的关键在于确保相关的值已经不在上下文里了,因此他在下次垃圾回收时会被回收。
三、隐藏类和删除操作
比如下面的代码:
function Article() {
this.title = 'INIcbud ciuwbi'; // 随便敲的
}
let a1 = new Article();
let a2 = new Article();
a2.author = 'Rose';
此时,两个 Article 实例就会对应两个不同的隐藏类,根据这种操作的频率和隐藏类的大小,这有可能对性能产生明显影响。
解决方案就是避免 JavaScript 的“先创建再补充(ready-fire-aim)”式的动态属性赋值,并在构造函数中一次性声明所有属性
function Article(opt_name) {
this.title = 'HQIOCNA CBIQCN';
this.name = opt_name;
}
let a1 = new Article();
let a2 = new Article("Rose");
由于 delete 关键字会导致生成相同的隐藏类片段,最佳实践是把不想要的属性设置为 null,这样可以保持隐藏类不变和继续共享,同时也能达到删除引用值供垃圾回收程序回收的效果。
function Article(opt_name) {
this.title = 'HQIOCNA CBIQCN';
this.name = opt_name;
}
let a1 = new Article();
let a2 = new Article("Rose");
a1.name = null;
四、选择 Object 还是 Map
- 内存占用方面
给定固定大小的内存,Map 大约可以比 Object 多存储 50%的键/值对 - 插入性能
Map 会稍微快一些 - 查找速度
代码设计大量查找操作,某些情况下选择 Object 更好一些 - 删除性能
如果代码涉及大量删除操作,那么应该选择 Map
五、弱映射(WeakMap)——DOM节点元数据
当节点从 DOM 树中被删除后,垃圾回收程序就可以立即释放内存。
const a = new WeakMap();
const loginButton = document.querySelector('#login');
// 给这个节点关联一些元数据
a.set(loginButton, {disabled: true});
六、创建新对象
- 使用 Object.setPrototypeOf()重写一个对象的原型继承关系
- 这会涉及所有访问了那些修改过 [[Prototype]]的对象的代码。
- 会造成性能下降
let a = { b: 2 };
let person = {
name: 'Rose'
};
Object.setPrototypeOf(person, a);
console.log(person.name); // Matt
console.log(person.b); // 2
console.log(Object.getPrototypeOf(person) === a); // true
- 为避免使用 Object.setPrototypeOf()可能造成的性能下降。可以通过 Object.create() 来创建一个新对象,同时为其指定原型
let a = { b: 2 };
let person = Object.create(a);
person.name = 'Rose';
console.log(person.name); // Matt
console.log(person.b); // 2
console.log(Object.getPrototypeOf(person) === a);