zoukankan      html  css  js  c++  java
  • JavaScript OOP闭包

    闭包

    “官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

    简单来说:

    • 函数执行时返回内部私有函数, 或者通过其他方式将内部私有函数保留在外(比如说通过将其内部私有函数的引用赋值外部变量),

       从而阻止该函数内部作用域等被执行引擎回收。

    • 在函数外部通过访问暴露在外的函数内部私有函数, 从而具有访问函数内部私有作用域的效果, 就是闭包。

      ES6之前, 通常我们实现的模块就是利用了闭包. 闭包依赖的结构有个鲜明的特点, 即: 一个函数在词法作用域之外执行。

     如下, f2是闭包的关键, 它的词法作用域便是函数f的内部私有作用域, 且它在f的作用域外部执行。

    var h = 1;
    function f(){
     var i = 2;
     return function f2(){
       var j = 3 + i + h;
       console.log(j);
     }
    }
    var ff = f();
    ff();//6

    由于定义时 f2 处于 f 的内部, 因此 f2 内可以访问到 f 的内部私有作用域, 这样通过返回 f2 就能保证在 f 函数外部也能访问到 i 变量.

    当f2执行时, 变量 j 处于scope chain的 index0的位置上, 变量 i 和变量 h 分别处于 scope chain 的 index1 index2 的位置上. 因此 j 的赋值过程其实就是沿着 scope chain 第二层 第三层 依次找到 i 和 h 的值, 然后将它们和3一起求和, 最终赋值给 j .

    浏览器沿着 scope chain 寻找变量总是需要耗费CPU时间, 越是 scope chain 的 外层(或者离f2越远的变量), 浏览器查找起来越是需要时间, 因为 scope chain 需要历经更多次遍历. 因此全局变量(window)总是需要最多的访问时间。

    ---------------------如果有兴趣的可以往下看-------------------------

    (以下内容并非原创,纯属来源于网上的朋友)

      如果要更加深入的了解闭包以及函数 f 和嵌套函数 f2 的关系,我们需要引入另外几个概念:函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。

    • 当定义函数 f 的时候, js解释器会将函数a的作用域链(scope chain)设置为定义 f 时 a 所在的”环境”, 如果 f 是一个全局函数,则scope chain中只有window对象。
    • 当执行函数 f 的时候, f 会进入相应的执行环境(excution context).
    • 在创建执行环境的过程中, 首先会为 f 添加一个scope属性, 即a的作用域, 其值就为第1步中的scope chain. 即a.scope=f 的作用域链.
    • 然后执行环境会创建一个活动对象(call object). 活动对象也是一个拥有属性的对象, 但它不具有原型而且不能通过JavaScript代码直接访问. 创建完活动对象后, 把活动对象添加到 f 的作用域链的最顶端. 此时a的作用域链包含了两个对象: f 的活动对象和window对象.
    • 下一步是在活动对象上添加一个arguments属性, 它保存着调用函数 f 时所传递的参数.
    • 最后把所有函数 f 的形参和内部的函数 f2 的引用也添加到 f 的活动对象上. 在这一步中, 完成了函数 f2 的定义, 因此如同第3步, 函数 f2 的作用域链被设置为 f2 所被定义的环境, 即 f 的作用域.

    到此, 整个函数 f 从定义到执行的步骤就完成了. 此时 f 返回函数 f2 的引用给 ff, 又函数 f2 的作用域链包含了对函数 f 的活动对象的引用, 也就是说 f2 可以访问到 f 中定义的所有变量和函数. 函数 f2 被 ff 引用, 函数 f2又依赖函数 f , 因此函数 f 在返回后不会被GC回收.

    当函数 f2 执行的时候亦会像以上步骤一样. 因此, 执行时 f2 的作用域链包含了3个对象: f2 的活动对象、f 的活动对象和window对象, 如下图所示:

    如图所示, 当在函数 f2 中访问一个变量的时候, 搜索顺序是:

    1. 先搜索自身的活动对象, 如果存在则返回, 如果不存在将继续搜索函数 f 的活动对象, 依次查找, 直到找到为止.
    2. 如果函数 f2 存在prototype原型对象, 则在查找完自身的活动对象后先查找自身的原型对象, 再继续查找. 这就是Javascript中的变量查找机制.
    3. 如果整个作用域链上都无法找到, 则返回undefined。
  • 相关阅读:
    变形方块
    Vim编辑器设置字体高亮显示
    从命令行终端获取数值作为函数参数
    Vi编辑器的使用技巧
    iOS开发常用shell命令
    include使用技巧
    交换2个整型变量的值
    C语言位运算实现函数体
    React Native 之文件内数据操作(var、let、const、static、Props、State、this)
    React Native 城市选择(四)获取城市名称
  • 原文地址:https://www.cnblogs.com/HuaKor/p/7905695.html
Copyright © 2011-2022 走看看