一直以来,对于Js的内存空间这部分的知识概念有些模糊,最近在回顾一些知识点的时候,特地的对js的内存这部分知识加深了一下理解,比如基本类型数据和引用类型数据在js内存中是怎么回事?什么是按值传递和按引用传递?以及对作用域和闭包的理解等等。
JavaScript的内存是怎样的?
JavaScript中有两种不同数据类型的值,一种是原始值,另外一种是引用类型值,原始值就是常说的基本数据类型值,包括String、Number、Boolean、Undefined和Null这五大基本数据类型,引用值指的是那些可能由多个指构成的对象,包括Object,Function,Array等类型的值。
JavaScript中的内存也分为栈内存和堆内存。一般来说,栈内存中存放的是存储对象的地址,而堆内存中存放的是存储对象的具体内容。对于原始类型的值而言,其地址和具体内容都存在与栈内存中;而基于引用类型的值,其地址存在栈内存,其具体内容存在堆内存中。堆内存与栈内存是有区别的,栈内存运行效率比堆内存高,空间相对堆内存来说较小,反之则是堆内存的特点。所以将构造简单的原始类型值放在栈内存中,将构造复杂的引用类型值放在堆中而不影响栈的效率。
我们看下下面Js的内存示意图:
1 | var a = 20; |
一开始看这道题,然后看答案,一脸懵逼啊有木有???为啥结果输出的是undefined和[object Object]???
了解了Js的变量在内存的存储形式之后,我们一起来解释一下:
1、a是一个引用类型的变量,一开始它在栈内存中的地址是指向堆内存的具体内容{n:1},接着赋值给b,所以b和a一样,此时都指向对象{n:1};
1 | var a = {n:1} ; |
2、接下来a.x = a = {n:2},我们都知道js的赋值运算是从右往左的,但“.”是优先级最高的运算符,所以这段代码先执行了a.x,所以此时对象{n:1}新增加了一个x的属性,并且值是undefined,所以运行到这里a和b都指向了对象{n:1,x:undefined};
1 | var a = {n:1,x:undefined} ; |
立即执行函数的作用就是建立一个独立的作用域,其一是为了防止全局污染,同时也可以防止过多的定义全局变量造成的内存回收问题。如果你的某些变量真的需要一直存在可以通过上面的方法挂载在window下。同样,你也可以传入jQuery进行使用。
手动解除变量的引用
1 | var obj = {a:1,b:2,c:3}; |
使用回调
除了使用闭包进行内部变量访问,回调函数也有这个功能。
1 | function getData(callback) { |
回调函数是一种后续传递风格(Continuation Passing Style, CPS)的技术,这种风格的程序编写将函数的业务重点从返回值转移到回调函数中去。而且其相比闭包的好处也不少:
- 如果传入的参数是基础类型(如字符串、数值),回调函数中传入的形参就会是复制值,业务代码使用完毕以后,更容易被回收;
- 通过回调,我们除了可以完成同步的请求外,还可以用在异步编程中,这也就是现在非常流行的一种编写风格;
- 回调函数自身通常也是临时的匿名函数,一旦请求函数执行完毕,回调函数自身的引用就会被解除,自身也得到回收。