JS 内存管理机制及验证

做用域

JavaScript 的变量被做用域所限制,若是超出了做用域,那么变量就没有办法再被使用,这样作的优势是:前端

  • 能够避免当前的变量转为全局变量
  • 有效限制变量的做用区域

而变量做用域也会按照声明方式的不一样,产生不一样的做用域:程序员

  • 未声明:全局变量
  • var 声明:做用域在 函数
  • letconst 声明:做用域在 {}

var 声明的变量

在函数内声明的变量其做用域会被限制在该函数的调用栈中,在外部没法直接获得该做用域内的变量。下面的例子中, fn 函数内的变量在全局下是没有办法查看的。面试

function fn() {
  var a = 1;
}
fn();
console.log(a); // 没法获得 fn 函数內的 a 变量

因此经常使用 "当即函数" 来限制变量的做用域,主要是避免全局变量的产生。segmentfault

(function() {
  var b = 1;
})();
console.log(b); // 没法获得 fn 函数內的 b 变量

let、const 声明的变量

ES6 以后所新增的letconst 做用域则与过去不一样,改用 {} 做为做限制用域的方式,这让 for 循环及部分语法避免产生多余的变量来影响做用域。数组

var 不一样的是 const 所定义的变量做用域被限制在 {} 中。因此这个例子中的变量 c 可在外部获得值,d 则没法取到。浏览器

{
  var c = 1;
  const d = 1;
}
console.log(c); // 1
console.log(d); // Uncaught ReferenceError: d is not defined,没法取到变量 d

内存管理机制

每当咱们新增一个变量时,在内存中就会占用一个位置来保存它的值,以便在程序后续运行时能够屡次使用。服务器

下面的代码会在内存中开辟一个 a 的空间来存储数字 1 的值。微信

var a = 1

流程以下:多线程

  1. 开辟一个内存空间来存放变量 a ,不过这时尚未赋值(缘由可参考:Hoisting)

image.png

  1. a 赋值。

image.png

全部的变量都会占用内存空间,除此以外对象、数组的属性以及函数参数等也会用相同的概念进行占用。调用一个函数时,每个函数的做用域也都会反复的进行内存占用。随着应用程序愈来愈复杂的状况下,若是持续的占用内存而没有进行适当的释放,那么内存可能会被耗尽。框架

JavaScript 引擎具备内存回收的机制,会释放再也不使用的变量内存,其基本概念为:当没有任何的引用指向它时就会释放内存。

来自MDN:collectible if there are zero references pointing to it.

内存释放的验证

下面用一个例子来讲明及验证内存释放的机制,首先用一段函数来产生一个很是长的字符串,长字符串会占用大量的内存空间。

在调用 randomString 函数后会返回一个很长的字串:

function randomString(length) {
  var result = '';
  var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  var charactersLength = characters.length;
  for (var i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

案例一:使变量维持在可引用的状态(不会释放内存)

定义一个全局变量 demoData,这个变量会持续维持可被引用的状态。

var demoData = []; // 全局变量
function getData() {
  for (let i = 0; i < 1000; i++) {
    demoData.push(randomString(5000))
  }
}
getData()
console.log(demoData); // 可引用 demoData 值

执行这段代码后,进入 Chrome DevTools 中的 Memory 页,这个功能能够获得当前页面所占用的内存情况。接下来点击 "Take snapshot" 按钮。

image.png

能够看到目前执行完这段代码后占用了 6.2MB 的内存空间(注意:任何浏览器环境和插件都会影响所占用的内存状态)。

image.png

案例二:使变量没法再次被引用(执行后释放内存)

限制变量的做用域,使变量没法再被外部引用。

此段代码依然会执行这个函数,也会将值赋值给变量,但外部没法再次引用 demoData 的值。

function getData() {
  var demoData = []; // 局部变量
  for (var i = 0; i < 1000; i++) {
    demoData.push(randomString(5000))
  }
}
getData();

而后回到 Memory 页点击 "Take snapshot" 从新取得内存的状态,接下来会获得与前面不一样的结果,此次只占用了 1.2MB 的内存(其中 5MB 被释放掉了)

image.png

总结

经过前面的例子,咱们知道了做用域以及内存之间的关系,而内存管理也是前端打工人必需要掌握的知识(除了控制内存的使用大小,还需在必要时保留而不被释放)。

173382ede7319973.gif


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章: