3
首发地址:https://github.com/jeuino/Blo...

前言

在上一篇《JavaScript 之作用域与作用域链》中,介绍了什么是作用域,以及变量和函数在作用域中是如何查找的。原来本篇文章是想写执行上下文中的变量对象的,但是想在介绍变量和函数是如何引用的之前,先总结一下它们是如何存储的。所以调整了一下发文顺序。

在 JavaScript 中,我们经常会声明变量和函数,JavaScript 引擎在处理声明时,会在内存中开辟一块空间,用于存储变量或函数。那么变量和函数到底存储在哪里?我们一起来看下。

内存空间

Image  7

首先我们需要了解几个概念:

  • 栈内存(stack):栈内存中数据的存取方式为先进后出,后进先出。这个过程就像给枪上子弹,先上的子弹最后打出,后上的子弹先打出。

Image  8

  • 队列(queue):队列中的数据存取方式与栈正好相反,它是先进先出,后进后出。就像火车过山洞,火车头先进同时也是先出的,车尾后进后出。

Image  9

  • 堆内存(heap):堆内存中数据的存取是无序的,不需要像栈和队列一样,必须按照某种顺序进行。你只需要知道存储数据的地址,那么就可以根据地址随时将数据取出。就像书架一样,你只需要知道书名,就可以在书架上找到并取出。

那么 JavaScript 中声明的变量和函数是存储在哪里的呢?

  • 基础数据类型(Undefined、Null、Boolean、String、Number):存储在栈中,按值访问。我们可以通过 JavaScript 直接操作保存在变量中的值。。
  • 引用数据类型(Object):存储在堆中,按引用访问。堆中的数据是不允许通过 JavaScript 直接访问的,我们平时在操作对象时,实际上操作的都是对象的引用(地址指针)。对象的引用存储在栈中。

我们看下面的例子:

var a = 0;
var b = 'test';
var c = {a: 1};
var d = [1,2,3];

Image  10

其中 a 和 b 两个基本数据类型数据存储在栈中;c 和 d 是引用类型,原始对象存储在堆中,并在栈中存储了引用地址。当我们访问 c 和 d 时,都需要先从栈中获取引用地址,然后根据引用地址到堆中找到相应的对象。

堆中原始的对象又是如何保存的呢?
堆中的原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。上面例子中变量ca属性,实际上是以下面的形式保存的:
Image

其中 [[value]] 属性保存的是该a属性的值。(其他的属性,我们暂时不关注)
我们再来看一个例子:

function foo() {
}
var obj ={
    foo: foo
}

这段代码中的 obj 对象是以下面的形式保存的:
Image  2

其中,函数在堆中是单独存储的。
对象的属性值 foo,存储的其实是该函数的引用地址。即使 foo 函数是直接定义在 obj 中的也是一样。严格来说这个函数并不属于 obj 对象。

下一篇

下篇文章将接着上篇继续介绍执行上下文中的变量对象。

传送门:《JavaScript 之变量对象》

参考:

JavaScript 的 this 原理

Jojo
126 声望12 粉丝

Stick a little bit more every day