zoukankan      html  css  js  c++  java
  • 作用域、闭包、内存泄露

      作用域

      作用域指的是变量的有效访问范围。作用域对Javascript有重要意义,了解作用域的工作原理是在性能角度和功能角度理解Javascript的关键。

      每一个JavaScript函数都被表示为对象,是一个函数实例。以下两种定义函数的方式是等价的。

    var sayName = function(){
        alert('hello world!');
    }
    
    var sayName = new Function('alert("hello world!")');

      函数对象正如其他对象那样,拥有可以被Javascript代码访问的属性,和一系列不能被Javascript代码访问,仅供JavaScript引擎使用的内部属性。其中一个内部属性是[[Scope]]。

      内部[[Scope]]属性包含一个函数被创建的作用域中对象的集合。此集合被称为函数的作用域链,它决定哪些数据可由函数访问。此函数作用域链中的每个对象被称为一个可变对象,每个可变对象都以“键值对”的形式存在。当一个函数创建后,它的作用域链被填充以对象,这些对象代表创建此函数的环境中可访问的数据。例如下面这个全局函数:

    function add(num1, num2) {
        var sum = num1 + num2;
        return sum;
    }

      当add()函数创建后,它的内部属性指向一个作用域链,该作用域链中被填入一个单独的可变对象,这个可变对象是一个全局对象。此全局对象包含诸如窗口、浏览器和文档之类的访问接口。

      

      而当add函数运行时会建立一个内部对象,称作“运行期上下文”。一个运行期上下文定义了一个函数运行时的环境。对函数的每次运行而言,每个运行期上下文都是独一的,所以多次调用同一个函数就会导致多次创建运行期上下文(execution context)。当函数执行完毕,运行期上下文就被销毁。

      一个运行期上下文有它自己的作用域链,用于标识符解析。当运行期上下文被创建时,它的作用域链被初始化。包括函数的[[Scope]]属性中所包含的对象会按照它们出现在作用域链中的顺序,被复制到运行期上下文的作用域链中。这项工作一旦完成,一个被称作“激活对象”的新对象就为运行期上下文创建好了。此激活对象作为函数执行期的一个可变对象,包含访问所有局部变量,命名参数,参数集合,和this的接口。然后,此对象被推入作用域链的前端。当作用域链被销毁时,激活对象也一同销毁。下图显示了add函数运行时所对应的运行期上下文和它的作用域链。

    var total = add(5, 10);

      

      需要记住的是两点:

    1. [[scope]]属性是函数创建到运行时一直存在的,知道函数被销毁后占用的内存才会被释放
    2. 运行期上下文只存在于函数运行期间,函数运行结束后该对象被销毁

      

      闭包、内存泄露

      闭包是JavaScript最强大的一个方面,它允许函数访问局部范围之外的数据。

    function assignEvents() {
        var id = "xdi9592";
        document.getElementById('save').onclick = function(event){
            saveDocument(id);
        }
    }

      当assignEvents()被执行时,一个激活对象被创建,并包含了该函数作用域内所有可访问的变量和函数,其中包括id变量。它将成为运行期上下文作用域链上的第一个对象,全局对象是第二个。当闭包创建时,[[Scope]]属性包含了作用域内所有对象的集合(等于assignEvents运行期上下文的作用域链,即assignEvents的激活对象,全局对象)。

      

      由于闭包的[[Scope]]属性包含与运行期上下文作用域链相同的对象引用,会产生副作用。通常,一个函数的激活对象与运行期上下文一同销毁。当涉及闭包时,运行期上下文对象,以及他的作用域链被销毁,但激活对象就无法销毁,因为引用仍然存在于闭包的[[Scope]]属性中。除非手动接触所有对匿名函数的引用,等到垃圾收集器下次运行时,assignEvents的激活对象才会随着匿名函数一同被销毁。

    document.getElementById('save').onclick = null;

      所以在Javascript代码中闭包与非闭包函数相比,需要更多内存开销。在大型网页应用中,这可能会导致内存泄露与难以排查的性能问题。

      随着浏览器的升级,大部分浏览器对于闭包引起的循环引用问题都能够顺利解决。但IE9之前使用非本地JavaScript对象实现DOM对象,对于Javascript对象跟DOM对象使用不同的垃圾收集器。所以闭包在IE的这些版本中发生循环引用时便会导致内存泄露。

      

  • 相关阅读:
    上传预览图片
    css3图片3D翻转效果
    获取新浪天气api显示天气情况(转)
    matlab添加M_map工具箱(转 http://blog.sina.com.cn/s/blog_491b86bf0100srt9.html)
    Matlab read_grib.r4 安装新方法(转自:http://blog.sina.com.cn/s/blog_9f36648b010179s7.html)
    grb文件的读取
    Windows 7 防火墙对Virtualbox guest的影响
    Virtualbox修改bios信息安装Windows XP OEM
    Wordpress编辑器(Tinymce)在Chrome中动态修改图片大小
    Android流行的框架整理
  • 原文地址:https://www.cnblogs.com/dojo-lzz/p/4509816.html
Copyright © 2011-2022 走看看