一, 基本类型和引用类型的值
1. 概念:
a. 基本类型: undefined,null,boolean,number,string. 基本类型值在内存中占据固定大小的空间, 因此被保存在栈内存中.
b. 引用类型: 保存在堆内存中的对象, 操作时是操作对象的引用而不是实际的对象.
2. 复制变量值:
a. 基本类型: 从一个变量向另一个变量复制基本类型的值, 会创建一个新值, 再把新值赋给新变量. 两个变量的值是相互独立的, 各自参与任何操作而互不影响.
b. 引用类型: 从一个变量向另一个变量复制引用类型的值, 只是复制了指向堆内存中一个对象的指针, 复制完成后两个变量实际上引用了同一个对象, 改变其中一个变量, 会影响另一个变量.
二, 执行环境及作用域链
1. 执行环境:
执行环境是 JavaScript 中的一个重要概念. 执行环境定义了变量或函数有权访问的其他数据, 决定了它们各自的生命周期. 每个执行环境都有一个与之关联的变量对象, 保存执行环境中定义的所有变量和函数. 开发人员无法访问该对象, 但解析器在处理数据时会用到它.
a. 执行环境有全局执行环境和函数执行环境之分. 全局执行环境是最外围的一个执行环境, 根据 ECMAScript 实现所在的宿主环境不同而不同. web 浏览器中全局执行环境是 window 对象, 所有的全局变量和函数都是作为其属性和方法创建的.
b. 每个函数都有自己的执行环境, 当执行流进入一个函数时, 函数的环境会被推入一个环境栈中. 而函数执行之后, 栈将其环境弹出, 把控制权返回给之前的执行环境.
c. 某个执行环境中的代码执行完毕后, 该环境被销毁, 保存其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出, 如关闭网页或浏览器时才销毁).
2. 作用域链:
当代码在一个执行环境中执行的时候, 会创建变量对象的一个作用域链, 有序保存执行环境有权访问的所有变量和函数.
a. 作用域链的前端, 始终是当前执行环境的变量对象. 后续的变量对象即来自其包
含环境, 以此延续到全局执行环境的变量对象.
b. 对于函数执行环境, 变量对象即活动对象, 最开始只保存一个变量, 即 arguments 对象(全局执行环境中不存在).
c. 在执行环境中需要读取写入变量时, 会从作用域最前端开始逐级查询, 局部执行环境找到则停止, 若没有找到继续沿着作用域链向上搜索, 直到全局执行环境的变量对象, 若也没有则报错.
d. 全局执行环境只能访问全局环境中定义的变量和函数, 不能直接访问局部环境中的任何数据.
e. 变量的执行环境有助于确定何时释放内存.
3. 局部变量的生命周期:
局部变量只在函数执行过程中存在, 这个过程中, 会为局部变量在栈 (或堆) 内存上分配相应的空间来储存. 函数执行结束, 局部变量销毁, 内存释放.
三, 垃圾收集
JavaScript 具有自动垃圾收集机制, 所需内存的分配和无用内存的回收完全实现自动管理. 原理是: 找出不再继续使用的变量, 然后释放其占用的内存. 为此, 垃圾收集器会按照固定时间间隔, 周期性执行这一操作. 垃圾收集器需要判断变量是否有存在的必要, 对无用变量打上标记, 以备将来回收内存.
方法:
1. 标记清除
JavaScript 中最常用的垃圾收集方式是标记清除. 垃圾收集器在运行的时候会给存储在内容中的所有变量都加上标记, 然后它会去掉环境中正在使用的变量以及被环境中变量引用的变量的标记. 而后再被加上标记的变量将被视为准备删除的变量, 最后垃圾收集器完成内存清除, 销毁带标记的值回收内存.
2. 引用计数
引用计数的含义是跟踪记录每个值被引用的次数. 当声明了一个变量并将一个引用类型值赋给该变量时, 则这个值的引用次数是 1. 如果同一个值又被赋给另一个变量, 则该值的引用次数加 1. 相反, 如果包含对这个值引用引用的变量又取得了另外一个值, 则这个值的引用次数减 1. 当这个值的引用次数为 0 时, 这说明没有办法访问这个值了, 其占用的内存就可以回收回来. 当垃圾收集器下次运行时, 就会释放那个值占用的内存.
问题: 循环引用
- function problem(){
- var obja=new Object();
- var objb=new Object();
- obja.someOtherObj=objb;
- objb.someOtherObj=obja;
- }
- // obja 和 objb 通过各自的属性相互引用, 两个对象的引用次数都是 2, 函数执行后两个对象都离开了作用域, 但他们的引用次数都不是 0, 不会被回收内存.
3. 管理内存
出于安全考虑, 防止运行 JavaScript 的网页耗尽全部系统内存而导致系统崩溃, 分配给 web 浏览器的可用内存通常要比分配给桌面应用程序的少. 内存限制问题不仅会影响给变量分配内容, 同时还会影响调用栈以及在一个线程中能够同时执行的语句数量, 固要优化内存占用.
优化方法:
解除引用: 为了确保页面性能, 执行中的代码只保存必要的数据, 一旦数据不有用, 就将其值设置为 null 来释放引用. 这个做法适用于大多数全局变量和全局对象的属性.(局部变量会在离开执行环境时自动被解除)
来源: http://www.qdfuns.com/article/46690/2694c4b3ea23647b6a042e84c1a0dcd4.html