zoukankan      html  css  js  c++  java
  • 关于闭包

    在看下面的内容,先要对执行环境(变量对象,作用域链)等有所了解。可以参考我之前写的执行环境。
    关于本文的闭包内容,首先推荐几篇资料。

    1预编译
    征途书上的资料,粗略的讲了下词法分析和语法分析,http://ajava.org/readbook/js/jszt/17035.html
    经过编译阶段的准备,JavaScript代码在内存中已经被构建为语法树,然后JavaScript引擎就会根据这个语法树结构边解释边执行了。
    在解释过程中,JavaScript引擎是严格 按着作用域机制来执行的。JavaScript语法采用的是词法作用域,也就是说JavaScript的变量和函数作用域是在定义时决定的,而不是执行时 决定的,由于词法作用域取决于源代码结构,所以JavaScript解释器只需要通过静态分析就能确定每个变量、函数的作用域,这种作用域也称为静态作用域。
    当JavaScript解释器执行每个函数时,先创建一个执行环境,在这个虚拟环境中创建一个调用对象,在这个对象内存储着当前域中所有局部变量、参数、嵌套函数、外部引用和父级引用列表upvalue等语法分析结构。
    实际上,通过声明语句定义的变量和函数在预编译 期的语法分析中就已经存储到符号表中了,然后把它们与调用对象中的同名属性进行映射即可
    调用对象的生命周期与函数的生命周期是一致的,当函数调用完毕且 没有外部引用的情况下,会自动被JavaScript引擎当做垃圾进行回收。

    2函数的Variable object在预编译阶段被创建的
    也就是上面说的 声明语句定义的变量和函数在预编译 期的语法分析中就已经存储到符号表中了
    一个网页上看到的 http://stephenwalther.com/blog/archive/2008/02/26/javascript-magic-properties-using-count-proto-and-parent.aspx
    A local variable defined in a function becomes a property of the function’s Variable object. The function’s Variable object gets created when a function is interpreted (not when the function is executed).
    函数的局部变量是函数的 变量对象 的属性,函数的变量对象 是在函数解释的时候被创建的,不是在函数执行的时候才开始创建的。

    3
    http://hi.baidu.com/lmzxf/blog/item/5841c7ef1c43d427adafd52c.html
    ,一个比较详细的流程。尤其那张图 


    4
    经典的闭包文章http://jibbering.com/faq/notes/closures/
    This would normally be the case upon exiting an execution context. The scope chain structure, the Activation/Variable object and any objects created within the execution context, including function objects, would no longer be accessible and so would become available for garbage collection.
    当退出执行环境的时候,任何在执行环境中创建的活动对象,作用域链,对象,以及函数对象,都不再可以被访问。这时就会被垃圾收集
    相对于函数来说,就是函数退出时,所有在函数中创建的对象都会被销毁,也就是没有内存保留。函数只被作为了一个运算过程。

    5winter大神的 http://www.cnblogs.com/winter-cn/archive/2008/07/07/1237168.html

    -

    -

    -

    -

    -

    实例,结合js高级2 上的第七章 闭包

    Closures are functions that have access to variables from another function ’ s scope。

    1关于静态作用域 

    function createComparisonFunction(propertyName) {
    return function(object1, object2){
    var value1 = object1[propertyName];
    var value2 =
    object2[propertyName];
    ........
    }
    }

    这里的着色的代码部分,能够访问到外部函数的参数propertyName,即使这个匿名函数被return到了其他地方。
    为什么呢?这是因为js是静态作用域的原因。这个匿名函数的作用域已经在定义时就决定了。

    2  关于执行过程
    当一个函数被调用的时候,就会创建一个执行环境,这个执行环境有一个[[scope]]属性,这个属性初始化了作用域链,活动对象被创建并添加到作用域链的顶部,下面是函数和图。其中的作用域链是一系列指向变量对象的指针。

    function compare(value1, value2){
    if (value1 < value2){return -1;}
    }
    var result = compare(5, 10);
    


    一旦函数执行结束,活动对象就会被摧毁,只剩下全局对象在内存中。

    3  闭包
    如果第一个函数加上以下代码,那情况就不一样了

    function createComparisonFunction(propertyName) {
    return function(object1){
    var value1 = object1[propertyName];
    ........
    }
    }
    
    var compareNames = createComparisonFunction(“name”);
    
    var result = compareNames({ name: “Nicholas” });
    
    compareNames = null;
    


    var compareNames = createComparisonFunction(“name”);这个是一个闭包

    执行这个函数时,创建createComparisonFunction函数的活动对象,创建匿名函数对象,这个匿名函数对象的作用域链引用了外部函数createComparisonFunction的活动对象
    如果这个匿名函数不被return,赋值给全局变量的话,那么外部函数的活动对象会像2中一样,随着函数的执行结束而销毁。
    而return给全局对象后,这createComparisonFunction函数的活动对象就不会被销毁。因为根据垃圾收集机制。存在引用的话就不会被回收。
    此时因为compareNames函数对象能被访问到,同时根据上面1中静态作用域的原因,这个函数对象的作用域链已经在创建时初始化了,保存了外部函数的活动对象
    因为活动对象没有被释放掉,所以内存中一直保存了。

    var result = compareNames({ name: “Nicholas” }, { name: “Greg”});
    执行这步时,创建compareNames函数的活动对象,执行结束后,被回收。

    如何释放掉内存呢?让引用指向别的地方就行了。compareNames现在引用函数对象,所以内存没法释放。compareNames=null就行了。

  • 相关阅读:
    Help-C#-属性-生成事件:预先生成事件和后期生成事件
    小说-长篇小说:《追风筝的人》
    散文-笔记:《皮囊》
    小说-励志:《妥协的力量》
    ons.ONSFactory.cs
    ons.ONSFactoryAPI.cs
    ons.ONSFactoryPorperty.cs
    System.Object.cs
    ons.MessageOrderListener.cs
    ons.MessageLisenter.cs
  • 原文地址:https://www.cnblogs.com/lunalord/p/1997925.html
Copyright © 2011-2022 走看看