javascript变量、作用域和内存问题

1-基本类型和引用类型的值

1.1、基本数据类型值:Undefined、Null、Boolean、Number和String;
1.2、引用数据类型值:Object

2-复制变量

2.1、变量赋复制基本数据类型值在这里插入图片描述
2.2、变量复制引用类型值
在这里插入图片描述
2.2.1、基本类型的值是直接存储在里面的,而引用类型的值是存储在里面。
2.2.2、由于js不允许直接操作对象的内存空间,所以在操作对象时,实际上是在操作对象的引用而不是实际的对象。
2.2.3、引用对象复制其实是复制了该对象的指针,而这个指针指向存储在堆中的一个对象,两个变量实际上将引用一个对象。

3-传递参数

3.1、ECMAScript中的所有函数的参数都是按传递,而访问变量有按值和按引用两种方式,但参数只能按传递。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.2、实际上,当函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁。
如不能理解上面的图请看下面例子。
在这里插入图片描述3.3、当函数内部对象重写obj时,就与之前obj指向的对象不一样啦。所有函数传参还是按值传递的。

4-执行环境及作用域

在这里插入图片描述
在这里插入图片描述
4.1、以上代码执行共涉及三个执行环境:全局环境、changeColor()的局部环境和swapColor的局部环境。全局环境下不能函数局部环境的变量,而局部环境则可以访问全局环境下的变量,当局部环境查找一个变量时,正好局部环境内没有这个变量,则向上一层查找,一直查找到全局环境下,这个就是作用域链

5-块级作用域

在这里插入图片描述
5.1、js中的if和for都没有块级作用域 内部的变量,在外部也可以被访问到。
在这里插入图片描述
5.2、如果初始化变量时没有使用var声明,则该变量会被自动添加到全局环境。

6-垃圾收集

6.1、标记清除:当变量进入环境(例如:当函数中声明一个变量)时,就将这个变量标记为"进入环境",从逻辑上说,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开时,则将其标记"离开环境"。
在这里插入图片描述
在这里插入图片描述
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
6.2、引用计数:当声明了一个变量并将一个引用类型值赋值该变量时,则这个值的引用次数就是1.如果同一个值又被赋给另外一个变量,则该值得引用次数加1。相反,如果包含对这个值引用的变量又取 得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾收集器下次再运行时,它就会释放那 些引用次数为零的值所占用的内存。
在这里插入图片描述
上述为我的理解,如有不对可指出

问题: 循环引用。 循环引用指的是对象A中包含一个指向对象B的指针, 而对象B中也包含一个指向对象A的引用。 请看下面这个例子
在这里插入图片描述
在这个例子中, objectA 和 objectB 通过各自的属性相互引用; 也就是说, 这两个对象的引用次数都是 2。

在采用标记清除策略的实现中, 由于函数执行之后, 这两个对象都离开了作用域, 因此这种相互引用不是个问题。 但在采用引用计数策略的实现中, 当函数执行完毕后, objectA 和 objectB 还将继续存在, 因为它们的引用次数永远不会是 0。

假如这个函数被重复多次调用, 就会导致大量内存得不到回收。 为此放弃了引用计数方式, 转而采用标记清除来实现其垃圾收集机制。 可是, 引用计数导致的麻烦并未就此终结。

IE 中有一部分对象并不是原生 JavaScript 对象。 例如, 其 BOM 和 DOM 中的对象就是使用 C++以 COM( Component Object Model, 组件对象模型) 对象的形式实现的, 而 COM对象的垃圾 收集机制采用的就是引用计数策略。

因此, 即使 IE的 JavaScript引擎是使用标记清除策略来实现的, 但 JavaScript访问的 COM对象依然是基于引用计数策略的。 换句话说, 只要在IE中涉及 COM对象, 就会存在循环引用的问题。

下面这个简单的例子, 展示了使用 COM对象导致的循环引用问题:
在这里插入图片描述
这个例子在一个 DOM元素( element) 与一个原生 JavaScript对象( myObject) 之间创建了循环引用。

其中, 变量 myObject 有一个名为 element 的属性指向 element 对象; 而变量 element 也有 一个属性名叫 someObject 回指 myObject。

由于存在这个循环引用, 即使将例子中的 DOM从页面中移除, 它也永远不会被回收。

为了避免类似这样的循环引用问题, 最好是在不使用它们的时候手工断开原生 JavaScript 对象与 DOM元素之间的连接。 例如, 可以使用下面的代码消除前面例子创建的循环引用:

在这里插入图片描述
将变量设置为 null 意味着切断变量与它此前引用的值之间的连接。 当垃圾收集器下次运行时, 就会删除这些值并回收它们占用的内存。

为了解决上述问题, IE9把 BOM和 DOM对象都转换成了真正的 JavaScript对象。 这样, 就避免了两种垃圾收集算法并存导致的问题, 也消除了常见的内存泄漏现象。

参考《 JavaScript高级程序设计》


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值