zoukankan      html  css  js  c++  java
  • 闭包

    古老定义

    1.  
      闭包(closure),是指函数变量可以保存在函数作用域内,因此看起来是函数将变量“包裹”了起来。
    2.  
      //根据定义,包含变量的函数就是闭包
    3.  
      function foo() {
    4.  
      var a = 0;
    5.  
      }
    6.  
      cosole.log(a)
    7.  
      // Uncaught ReferenceError: a is not defined
    8.  
       

    《JavaScript高级程序设计》对闭包定义

    闭包是指有权访问另一个函数作用域中的变量的函数

    1.  
      //根据《JavaScript高级程序设计》,访问上层函数的作用域的内层函数就是闭包
    2.  
      function foo() {
    3.  
      var a = 2;
    4.  
      function bar() {
    5.  
      console.log(a);
    6.  
      }
    7.  
      bar();
    8.  
      }
    9.  
      foo();

    《JavaScript权威指南》对闭包定义

    函数对象可以通过作用域链相互关联起来,函数体内部变量可以保存在函数作用域内,这就是闭包。

    1.  
      var global = "global scope"; //全局变量
    2.  
      function checkscope() {
    3.  
      var scope = "local scope"; //局部变量
    4.  
      function f() {
    5.  
      return scope; //在作用域中返回这个值
    6.  
      };
    7.  
      return f();
    8.  
      }
    9.  
      checkscope(); // 返回 "local scope"

    严格来说,闭包需要满足三个条件:【1】访问所在作用域;【2】函数嵌套;【3】在所在作用域外被调用
      有些人觉得只满足条件1就可以,所以IIFE是闭包;有些人觉得满足条件1和2才可以,所以被嵌套的函数才是闭包;有些人觉得3个条件都满足才可以,所以在作用域以外的地方被调用的函数才是闭包


    为什么我们需要闭包

    首先来看一个例子,我们来实现一个计数器。

    1.  
      var counter = 0;
    2.  
      function add() {
    3.  
      return counter += 1;
    4.  
      }
    5.  
      add();
    6.  
      add();
    7.  
      add();// 计数器现在为 3

    现在我们已经达到了目的,可是问题来了,代码中的任何一个函数都可以随意改变counter的值,所以这个计数器并不完美。那我们把counter放在add函数里面不就好了么?

    1.  
      function add() {
    2.  
      var counter = 0;
    3.  
      return counter += 1;
    4.  
      }
    5.  
      add();
    6.  
      add();
    7.  
      add();// 本意是想输出 3, 但输出的都是 1

    所以这样做的话,每次调用add函数,counter的值都要被初始化为0,还是达不到我们的目的。

    如何使用闭包

    所以这时候我们就要用闭包去解决这个问题了,先看代码。

    1.  
      var add = (function () {
    2.  
      var counter = 0;
    3.  
      return function () {return counter += 1;}
    4.  
      })();
    5.  
      add();
    6.  
      add();
    7.  
      add();// 计数器为 3

    这时候我们完美实现了计数器。这段非常精简,可以拆分成如下等价代码。

    1.  
      function outerFunction () {
    2.  
      var counter = 0;
    3.  
      function innerFunction (){
    4.  
      return counter += 1;
    5.  
      }
    6.  
      return innerFunction;
    7.  
      }
    8.  
      var add = outerFunction();
    9.  
      add();
    10.  
      add();
    11.  
      add();// 计数器为 3

    这时候的add就形成了一个闭包。一个闭包由两部分组成,函数和创建该函数的环境。环境是由环境中的局部变量组成的。对于闭包add来说,它由函数innerFunction和变量counter组成,所以这时候add是可以访问变量counter的。

    使用闭包应注意的问题

    由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。因此可以手动解除对匿名函数的引用,以便释放内存。

      1.  
        function f2(){
      2.  
        var n=22;
      3.  
        var nAdd=function(){n++};
      4.  
        return function(){
      5.  
        return {
      6.  
        n:n,
      7.  
        nAdd:nAdd
      8.  
        }
      9.  
        }
      10.  
        }
      11.  
        //result2就是创建了一个匿名函数
      12.  
        var result2=f2();
      13.  
        //调用函数
      14.  
        console.log(result2());
      15.  
        result2().nAdd();
      16.  
        console.log(result2());
      17.  
        //解除对匿名函数的引用,以便释放内存
      18.  
        result2=null;
  • 相关阅读:
    机器学习(深度学习)
    机器学习(六)
    机器学习一-三
    Leetcode 90. 子集 II dfs
    Leetcode 83. 删除排序链表中的重复元素 链表操作
    《算法竞赛进阶指南》 第二章 Acwing 139. 回文子串的最大长度
    LeetCode 80. 删除有序数组中的重复项 II 双指针
    LeetCode 86 分割链表
    《算法竞赛进阶指南》 第二章 Acwing 138. 兔子与兔子 哈希
    《算法竞赛进阶指南》 第二章 Acwing 137. 雪花雪花雪花 哈希
  • 原文地址:https://www.cnblogs.com/llcc/p/13432269.html
Copyright © 2011-2022 走看看