JavaScript学习系列以内存模型篇

一个热爱技术的菜鸟...用点滴的积累铸就明日的达人javascript

正文
  若是真的想学好一门语言,那么必定要了解它内存模型,本篇文章就带你走进JavaScript的内存模型,因为本人才疏学浅,如有什么表述有误的地方,欢迎各位看官可以指点一二,在此不胜感激...
  在阅读这边文章以前,默认您已经掌握了JavaScript的基本概念、栈堆等基本数据结构以及计算机基本理论基础,若有了解欠缺,请移步相关博客后再阅读本文。
1、基本的数据类型的内存结构
  首先粗略的介绍一下JavaScript中五种基本的数据类型Undefined、Null、Boolean、Number、String;其中对于Undefined与Null的区别,网上有不少大牛都有介绍,在此本文暂不涉及,若有疑虑之处,请移步相关博客。或许有看官会问为何在介绍JavaScript内存模型以前要先介绍JavaScript的基本数据类型的内存结构呢?这是由于JavaScript内存模型与基本数据类型的内存结构的关系就比如数学与实数的关系,基本数据类型的内存结构是整个JavaScript内存模型的基础。那么接下来就让我以最简短的方式来阐述一下基本数据类型的内存结构吧~
  基本数据类型的内存结构:在JavaScript中基本的数据类型都是以值的形式保存在内存中的。举个例子:
 
var inta = 10;
var strb = 'Hello';

  那么在执行完这段JavaScript代码以后,内存中会有两个区域分别表示为inta,strb;其中表示inta区域的值为‘10’,表示strb区域的值为‘Hello’,也即表示inta与strb的内存区域保存的均为实际的真值; java

2、引用数据类型的内存结构算法

  在JavaScript中除了基本数据类型,那就剩下引用数据类型了,因此在介绍玩基本数据类型内存结构以后,就颇有必要再介绍一下引用数据类型内存结构。引用数据类型的真实对象是保存在堆内存中的,而JavaScript与Java类似,均不能够直接访问堆内存,因此都是使用“引用”这个东西来访问处于堆中的对象,引用与对象的关系能够描述成遥控器与电视机之间的关系,咱们能够持有遥控器来操控电视机。所谓的引用其实就是一块内存的地址,即在表示引用的区域上保存的是内存中对象的内存地址值,如图所示:浏览器

  其中假设对象处于内存中一个位置叫作0x23215的区域,那么椭圆的区域表示这个对象的引用,椭圆区域中存的就是0x23125这个值,在实际的操做中执行环境会经过引用中存的0x23125,去找到内存中的这个对象。数据结构

3、内存模型闭包

  在JavaScript执行时期,能够将内存从逻辑上划分为两部分:栈与堆。其中栈是在JavaScript执行时,用于储存执行上下文(后续文章会介绍)的,而堆是存储对象的区域。在执行上下文生成以后,会建立一个变量对象(后续文章会介绍),变量对象是一个特殊的对象,它也会存储在堆。基本数据类型每每都会直接保存在变量对象中,而引用数据类型其实是在变量对象中保存一个引用指向对象的地址(也即引用自己)。函数

 

  学习完JavaScript中的内存模型以后,请各位看官看看下面这段代码,而且猜猜它的输出结果,以验证上述知识的理解程度:性能

var inta = 10;
var stra = 'Hello';

var obja = {a: 10, b: 'Hello'};

var intb = inta;
var strb = stra;
var objb = obja;

intb = 20;
strb = 'World';
objb.a = 20;
objb.b = 'World';

console.log(inta, intb);
console.log(stra, strb);
console.log(obja, objb);

  运行结果:学习

10 20
Hello World
{ a: 20, b: 'World' } { a: 20, b: 'World' }

  这其中会涉及到对象的赋值问题,在对基本数据类型赋值的时候,都是将原值赋值到新的对象上,因此改变新的对象的值,并不会影响到原值(由于它们本质上保存的是两个值);而对引用数据类型赋值则是将引用所指向对象的地址赋值给另外一个引用,而在后续操做中,若是经过新的引用去改变对象中内部的值的话,仍是会影响原来的引用所指向的对象(由于它们本质上保存的是同一个对象)spa

4、内存回收机制

  JavaScript具备自动的垃圾回收机制,也即执行环境会负责代码的执行过程当中使用的内存,它会按期(周期性)找出哪些再也不使用的对象,而后释放其内存。目前JavaScript最经常使用的垃圾回收算法为标记清除算法,垃圾回收机制会经过标记的算法来决定哪些对象是不须要再次使用的,而后再进行清除,也即清理哪些被定义为垃圾的JavaScript对象。

  上述所述的再也不使用的变量也就是生命周期结束的变量,固然只多是局部变量。全局变量的生命周期直到浏览器卸载页面才会结束,因此声明一个全局变量的时候,咱们必定要慎重的考虑,在使用完这个变量的对象以后,咱们是否还在须要这个对象,若是不须要的话,咱们应该手动的将这个变量置为空,这样在下一次垃圾回收的时候,就能去释放这个变量上一次指向的对象(请注意变量与对象的区别)。

  下面请各位看官see一下如下的代码,来分析一下垃圾回收。

function fun1() {
    var obj = {name: 'csa', age: 24};
}

function fun2() {
    var obj = {name: 'coder', age: 2}
    return obj;
}

var f1 = fun1();
var f2 = fun2();

  在上述代码中,当执行var f1 = fun1();的时候,执行环境会建立一个{name:'csa', age:24}这个对象,当执行var f2 = fun2();的时候,执行环境会建立一个{name:'coder', age=2}这个对象,而后在下一次垃圾回收来临的时候,会释放{name:'csa', age:24}这个对象的内存,但并不会释放{name:'coder', age:2}这个对象的内存。这就是由于在fun2()函数中将{name:'coder, age:2'}这个对象返回,而且将其引用赋值给了f2变量,又因为f2这个对象属于全局变量,因此在页面没有卸载的状况下,f2所指向的对象{name:'coder', age:2}是不会被回收的。

  因为JavaScript语言的特殊性(闭包...),致使如何判断一个对象是否会被回收的问题上变的异常艰难,这不只须要咱们有很强的基本功,还须要在之后的项目中积累经验。最后顺便说一句,即便随着硬件的更新换代以及垃圾回收机制的改进,咱们也不该该忽视垃圾回收的基本理论,由于这是提升代码性能的关键一步,只有这样咱们才能写出那些堪称艺术品的代码...

相关文章
相关标签/搜索