zoukankan      html  css  js  c++  java
  • 闭包(Closure)

    闭包是JavaScript的一大难点,也是它的特色。利用闭包可以实现许多高级应用。今天我们就一起来讨论一下有关闭包的问题。


    一.闭包的概念

    很多语言中都有闭包,概念也不尽相同。就JS闭包的概念也有好多种,下面一种我认为是比较好理解也比较精确的一种。

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

    这句话可以分为两步来理解:
    1)闭包是函数;
    2)这个函数可以访问另一个函数作用域中的变量。

    等等,作用域又是什么鬼。。。

    第二点翻译一下就是可以访问另一个函数内部定义的变量。下面再解释什么是作用域。

    示例代码:

    function outer() {
        var name = "Foolgry";
        
        function inner() {
            return name;
        }
    }
    

    从技术层面来说,上面的inner已经是一个闭包了。
    1)它是一个函数;
    2)它可以访问outer内部定义的变量name
    但是,大多数人习惯的闭包是下面这个样子的:

    示例代码:

    function outer() {
        var name = "Foolgry";
        
        function inner() {
            return name;
        }
        return inner;
    }
    
    var getName = outer(); 
    
    getName(); // "Foolgry"
    

    这个inner肯定是闭包,它不仅满足上面的两个条件,还具备一个特征:即使outer运行后被回收,它能够保证name在内存中继续存在。
    每个人都有不同的理解,有的人认为只有第二个例子才算闭包,第一个例子不算。我的理解是都可以算做闭包。

    闭包本身并不难理解,难得是它和作用域this等问题放在一起。
    说起闭包,就不得不谈一些基础问题,比如:上面提到的作用域


    二.作用域

    JS中有两种作用域,全局作用域和局部作用域。

    示例代码:

    var name = "Bob",//全局作用域下定义的变量(全局变量)
        age = 99,
        sex = "female";
    function object() {
        var name = "Foolgry"; //局部作用域下定义的变量(局部变量)
        
        alert(name); // "Foolgry"
        alert(age); // 99
        alert(sex); // undefined
        
        var sex = "male",
            job = "fe"
    }
    alert(name);  // "Foolgry"
    alert(job); // error
    
    • object作用域中,name是局部变量,虽然全局环境中也定义了变量name,但是在局部作用域中,会优先访问局部变量;

    • 如果访问不到,才找全局变量,如age一样;

    • sex为什么是undefined呢?因为JS中有一种机制叫做变量提升。这东西会把上面几句话变成这样:

        var sex;
        alert(sex);
        sex = "male";
      
    • 访问job发生错误,是因为一般情况下局部变量只能在其函数作用域内部访问,这也是为什么需要闭包了。


    三.闭包应用

    闭包的应用有很多,这里只列举其中两种:

    • 模块化代码,减少全局变量的污染
    • 私有成员的存在

    四.闭包需要注意的问题

    1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

    2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。


    五.闭包经典例子

    function fun(n,o) {
        console.log(o);
            return {
                fun:function(m) {
                    return fun(m,n);
                }
            };
    }
    var a = fun(0); a.fun(1);  a.fun(2);  a.fun(3);  
    var b = fun(0).fun(1).fun(2).fun(3);
    var c = fun(0).fun(1);  c.fun(2);  c.fun(3);
    

    问:三行a,b,c的输出分别是什么?

    这个例子如果你能全部答对,那么JS闭包就没什么问题了。

    undefined,0,0,0
    undefined,0,1,2
    undefined,0,1,1
    

    下一篇文章讨论一下这题解法。

  • 相关阅读:
    Codeforces Round #649 (Div. 2) D. Ehab's Last Corollary
    Educational Codeforces Round 89 (Rated for Div. 2) E. Two Arrays
    Educational Codeforces Round 89 (Rated for Div. 2) D. Two Divisors
    Codeforces Round #647 (Div. 2) E. Johnny and Grandmaster
    Codeforces Round #647 (Div. 2) F. Johnny and Megan's Necklace
    Codeforces Round #648 (Div. 2) G. Secure Password
    Codeforces Round #646 (Div. 2) F. Rotating Substrings
    C++STL常见用法
    各类学习慕课(不定期更新
    高阶等差数列
  • 原文地址:https://www.cnblogs.com/foolgry/p/5304425.html
Copyright © 2011-2022 走看看