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


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

    • 基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。
    • 在很多语言中,字符串以对象的形式来表示,因此被认为是引用类型的。ECMAScript 放弃了这一传统。

    1.1 动态的属性

    //引用类型
    var person = new Object();
    person.name = "Nicholas";
    alert(person.name); //"Nicholas"
    
    //基本类型
    var name = "Nicholas";
    name.age = 27;
    alert(name.age); //undefined
    

    1.2 复制变量值

    //基本类型
    var num1 = 5;
    var num2 = num1;
    num1=3;
    alert(num2); //"5"
    
    //引用类型
    var obj1 = new Object();
    var obj2 = obj1;
    obj1.name = "Nicholas";
    alert(obj2.name); //"Nicholas"
    

    1.3 传递参数

    //证明引用类型也是值传递
    function setName(obj) {
        obj.name = "Nicholas";
        obj = new Object();
        obj.name = "Greg";
    }
    var person = new Object();
    setName(person);
    alert(person.name); //"Nicholas"
    

    1.4 检测类型

    //检测基本类型
    var s = "Nicholas";
    var b = true;
    var i = 22;
    var u;
    var n = null;
    var o = new Object();
    alert(typeof s); //string
    alert(typeof i); //number
    alert(typeof b); //boolean
    alert(typeof u); //undefined
    alert(typeof n); //object
    alert(typeof o); //object
    
    //检测引用类型
    alert(person instanceof Object); // 变量 person 是 Object 吗?
    alert(colors instanceof Array); // 变量 colors 是 Array 吗?
    alert(pattern instanceof RegExp); // 变量 pattern 是 RegExp 吗?	
    
    • 根据规定,所有引用类型的值都是 Object 的实例。
      因此,在检测一个引用类型值和 Object 构造函数时, instanceof 操作符始终会返回 true。
      当然,如果使用 instanceof 操作符检测基本类型的值,则该操作符始终会返回 false,因为基本类型不是对象。

    2. 执行环境及作用域

    • 作用域链;
    • 执行环境;
    • 全局环境;
    • 活动对象;

    2.1 延长作用域链

    当执行流进入下列任何一个语句时,作用域链就会得到加长:
    1. try-catch 语句的 catch 块;
    2. with 语句。
    
    function buildUrl() {
        var qs = "?debug=true";
    
        with(location){
                var url = href + qs;
        }
    
        return url;
    }
    

    2.2 没有块级作用域

    2.2.1 声明变量
    • 使用 var 声明的变量会自动被添加到最接近的环境中。
      在函数内部,最接近的环境就是函数的局部环境;在 with 语句中,最接近的环境是函数环境。
      如果初始化变量时没有使用 var 声明,该变量会自动被添加到全局环境。

    • 在编写 JavaScript 代码的过程中,不声明而直接初始化变量是一个常见的错误做法,因为这样可能会导致意外。
      我们建议在初始化变量之前,一定要先声明,这样就可以避免类似问题。
      在严格模式下,初始化未经声明的变量会导致错误。

    2.2.2 查询标识符
    • 向上搜索作用域链;
    • 变量查询也不是没有代价的。
      很明显,访问局部变量要比访问全局变量更快,因为不用向上搜索作用域链。
      JavaScript 引擎在优化标识符查询方面做得不错,因此这个差别在将来恐怕就可以忽略不计了。

    3 垃圾收集

    3.1 标记清除

    • 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。
      然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。
      而在此之后再被加上标记的变量将被视为准备删除的变量。

    • 到 2008 年为止, IE、 Firefox、 Opera、 Chrome 和 Safari 的 JavaScript
      实现使用的都是标记清除式的垃圾收集策略(或类似的策略),只不过垃圾收集的时间间隔互有不同。

    3.2 引用计数

    //循环引用示例
    function problem(){
        var objectA = new Object();
        var objectB = new Object();
        objectA.someOtherObject = objectB;
        objectB.anotherObject = objectA;
    }
    
    • 内存泄漏;

    3.3 性能问题

    • 随着 IE7 的发布,其 JavaScript 引擎的垃圾收集例程改变了工作方式:
      触发垃圾收集的变量分配、字面量和(或)数组元素的临界值被调整为动态修正。
      IE7 中的各项临界值在初始时与IE6相等。如果垃圾收集例程回收的内存分配量低于15%,
      则变量、字面量和(或)数组元素的临界值就会加倍。
      如果例程回收了 85%的内存分配量,则将各种临界值重置回默认值。
      这一看似简单的调整,极大地提升了 IE在运行包含大量 JavaScript 的页面时的性能。

    • 事实上,在有的浏览器中可以触发垃圾收集过程,但我们不建议读者这样做。
      在IE 中,调用 window.CollectGarbage()方法会立即执行垃圾收集。
      在 Opera 7 及更高版本中,调用 window.opera.collect()也会启动垃圾收集例程。

    3.4 管理内存

    function createPerson(name){
        var localPerson = new Object();
        localPerson.name = name;
        return localPerson;
    }
    
    var globalPerson = createPerson("Nicholas");
    
    // 手工解除 globalPerson 的引用	
    globalPerson = null;
    
    • 不过,解除一个值的引用并不意味着自动回收该值所占用的内存。
      解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

    4. 小结

    • 基本类型值和引用类型值

      1. 基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;
      2. 引用类型的值是对象,保存在堆内存中;
    • 执行环境

      1. 执行环境有全局执行环境和函数执行环境之分;
      2. 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
      3. 变量的执行环境有助于确定应该何时释放内存;
    • 垃圾收集例程

      1. “标记清除”是目前主流的垃圾收集算法;
      2. “引用计数”容易导致“循环引用”,JavaScript 引擎目前都不再使用这种算法,
        但在 IE 中访问非原生 JavaScript 对象时,这种算法可能仍然会导致问题;
      3. 接触变量的引用有助于消除“循环应用”现象;
  • 相关阅读:
    React + Webpack搭建环境
    iOS 中block中使用了外部变量的分析
    研究Extension和Category的一个例子
    43. Multiply Strings
    安装cocoapods
    iOS推送流程
    iOS中富文本NSMutableAttributedString的用法
    用杯赛尔曲线(做动画和绘图)
    字符串转换为长整型 strtol
    使用DirectUI
  • 原文地址:https://www.cnblogs.com/huoteng/p/4956722.html
Copyright © 2020-2023  润新知