乐趣区

JavaScript高级程序设计笔记变量作用域内存问题

一、写在前面

最近研究了创建 Android 虚拟机、vscode 结合 weex 开发 Android APP、Vmware 装 MAC 虚拟机的事,看的内容不够多,接下来加油

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

2.1 基本类型、引用类型

  • 变量类型:

    • 基本类型:简单数据段,按值访问的,可操作变量中的实际值
    • 引用类型:对象,按引用访问,操作对象的引用,能动态添加属性
  • 变量复制:

    • 基本类型:直接分配两个内存空间,互不影响
    • 引用类型:复制了指针,指向堆中同一对象,相互影响
  • 传参(见示例):

    • 基本类型传值,互不影响
    • 引用类型传地址,相互影响
// 示例
function setName(obj) {
    // 指向 person,添加属性 name
    obj.name = "Nicholas";
    // 指针指向新的内存空间
    obj = new Object();
    obj.name = "Greg";
    
    // 函数执行完毕后,局部对象立即销毁
}

var person = new Object();
setName(person);
alert(person.name);    //"Nicholas"
  • 检测类型

    • typeOf 特殊:null 返回 object
    • instanceof:引用类型检测,(某实例)instanceof(某类型)

2.2 执行环境、作用域

  • 执行环境:定义变量或函数有权访问的其他数据范围,决定行为。中有变量对象,保存环境中定义的所有变量和函数,环境销毁,变量、函数销毁

    • 全局执行环境,web 中为 window 对象
    • 局部执行环境,执行流进入函数,函数环境被推入环境栈,执行后,栈将其环境弹出,控制权返回之前的执行环境
  • 作用域链:在环境中执行代码,会创建变量对象的作用域链,保证(有权访问当前环境的)变量和对象有序访问

作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation
object)作为变量对象。活动对象在最开始时只包含一个变量,即 arguments 对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象

  • 标识符解析:沿作用域链一级一级搜索标识符。从作用域链前端开始,逐级向后,直到找到标识符为止
  • 内外关系:

    • 内部环境可以通过作用域链访问所有外部环境,外部环境不能访问内部环境中的任何变量或函数
    • 每个环境可以向上级搜素,但不能向下搜索进入另一个执行环境

2.3 延长作用域链

在作用域链前端加临时变量对象,执行后移除

  • try-catch 中 catch
  • with
function aaa( ) {
    var qs = '?id=12';
    // 引用 location,with 内部可用 location 的所有属性和方法
    with(location) {
        // href 为 locaiton.href
        var url = href + qs;
    }
   // 在 aaa()内可拿到 with()内定义的 url
    return url;
}
  • catch 特殊情况:IE8 以前 catch 的错误对象会添加至执行环境的变量对象,catch 外也能访问(IE9 修复了)

2.4 没有块级作用域

{} 封闭的代码块中定义的变量,执行后没有被销毁,依旧存在于 {} 外部执行环境中

  • 声明变量

    • var:自动添加到最接近的环境中。没有 var 直接声明,添加到全局环境中(严格模式下导致错误,不推荐)
  • 查询标识符

    • 从作用域链前端开始,向上逐级查询,直至匹配为止(先自身再向上)
    • 访问局部变量比访问全局变量更快

2.5 垃圾收集

执行环境管理着代码执行过程中使用的内存
自动垃圾收集机制:实现所需内存分配、无用内存回收,自动管理。固定时间间隔,周期性检索不再继续使用的变量,打标记,释放其占用的内存

  • 回收策略

    1. 标记清除(主流)

      • 变量进入环境、离开环境,标记不同
      • 标记方式:翻转某位,或以环境列表、离开环境列表区分,或其他
      • 运行机制:内存中全部变量加标记,再去掉环境中的、被环境中引用的变量的标记,剩下还有标记的,准备删除,垃圾收集器清除内存,销毁值,回收空间
    2. 引用计数(不常见)

      • 跟踪每个值被引用的次数
      • 计数规则:引用类型的值赋给一个变量,引用次数加一;已经引用的变量不再引用它,引用次数减一
      • 运行机制:垃圾收集器运行,释放引用次数为 0 的值所占的内存。
      • 特殊情况:

        • 循环引用(例:两对象间相互引用,则引用次数永不为 0,无法销毁)
        • IE9 之前,BOM、DOM 对象以 COM(使用引用计数策略)形式实现,循环引用后删除 DOM,对应值也不会回收(通过赋值 null,手动断开循环引用解决)。IE9 后,BOM、DOM 转为真正的 js 对象,避免了该问题
  • 性能问题

    • IE7 之前:内存分配量达到任一临界值(256 变量、4096 对象数组、64K 字符串)则回收,缺点:如一直在临界值之上,则一直回收
    • IE7 修正:临界值动态修正,初始与之前相等,回收的分配量低于 15%,临界值加倍,回收的内存分配量 85%,临界值恢复初始
    • 手动触发方式(不推荐):
// 手动触发方式
// IE
window.CollectGarbage();
// Opear7~
window.opera.collect();
  • 管理内存

    • 内存分配:给 web 浏览器的少于给桌面应用的,防止系统崩溃
    • 优化内存占用:只保存必要数据,不用的置 null(解除引用,给全局中的用,局部的会自动销毁),等待下一次垃圾回收
退出移动版