Skip to content

其他

垃圾回收机制

只有函数内的变量才能被回收,也就是局部变量的生命周期结束;

两种回收机制

  • 标记清除:变量进入环境时标记“进入”,变量离开环境时,标记“离开”;
  • 引用计数:当变量 A(引用类型)赋值给了变量 B,则 A 引用次数 +1;当 B 不再指向A时,A 引用次数 -1;
javascript
// 标记清除
function test(){
  const a = 10 ; // 被标记,进入环境 
}
test(); // 执行完毕 之后 a 又被标离开环境,被回收

// 引用计数 (很少使用了)
function test() {
  var a = {};    // a指向对象的引用次数为1
  var b = a;     // a指向对象的引用次数加1,为2
  var c = a;     // a指向对象的引用次数再加1,为3
  var b = {};    // a指向对象的引用次数减1,为2
}

内存泄漏

循环引用、闭包、DOM 泄露、定时器泄漏

javascript
// 意外的全局变量:在函数中没有声明就赋值的变量,或者通了 this 声明,但最后挂到 window 上了

// 闭包,维持函数内部局部变量,使其无法释放
function bindEvent() {
  const obj = document.createElement('XXX');
  const unused = function () {
    console.log(obj, '闭包内引用obj obj不会被释放');
  };
  obj = null;  // 解决方法
}

// 定时器泄漏
const someResource = getData(); 
const t = setInterval(function() { 
    const node = document.getElementById('Node'); 
    if (node) { 
      node.innerHTML = JSON.stringify(someResource)); // 处理 node 和 someResource 
    } 
  }, 1000);
clearInterval(t); // 如果不关计时器,node 对象和回调函数都不会被回收

// 对 DOM 元素的监听,当不监听的时候,取消事件监听
// 对 DOM 元素的引用,不需要时取消应用

设计模式

1️⃣ 工厂模式

javascript
function createPerson(name, age, job) {
  const obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.job = job;
  obj.sayName = function () { console.log(this.name); };
  return obj;
}

const person1 = createPerson("Nicholas", 29, "Software Engineer");
const person2 = createPerson("Greg", 27, "Doctor");

这种工厂模式虽然可以解决创建多个类似对象的问题,但没有解决对象标识问题(即新创建的对象是什么类型)

2️⃣ 构造函数模式

javascript
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () { console.log(this.name); };
}
const person1 = new Person("Nicholas", 29, "Software Engineer");
const person2 = new Person("Greg", 27, "Doctor");
person1.sayName();  // Nicholas 
person2.sayName();  // Greg

Person 构造函数内部代码和 createPerson 工厂函数基本一致,只是有以下区别:

  • 没有显式地创建对象
  • 属性和方法直接复制给了 this
  • 没有 return

构造函数的问题在于其定义的方法会在每个实例上都创建一遍,造成资源浪费

3️⃣ 原型模式

javascript
function Person() { };
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () { console.log(this.name); };

const person1 = new Person();
person1.sayName(); // "Nicholas" 
const person2 = new Person();
person2.sayName(); // "Nicholas" 
console.log(person1.sayName == person2.sayName); // true