闭包_使用闭包

许多编程语言使用私有变量,这些私有变量是对外部隐藏的对象属性。这是非常有用的一种特性,因为当通过其他代码访问这些代码时,我们不希望对象的实现细节对用户造成过度符合.遗憾的是,原生JavaScript不支持私有变量。
但是,通过使用闭包,我们可以实现很接近的,可接受的私有变量,示例代码如下面例子所示。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../unitl/test.js"></script>
    <style>
        #results li.pass {color:green;}
        #results li.fail {color:red;}
    </style>


</head>

<body>
    <ul id="results"></ul>
</body>
<script>

    // 定义ninja构造函数。
    function Ninja() {

        //在构造函数内部声明一个变量,因为所声明的变量的所有域局限于构造函数的内部,所以它是一个“私有”变量。我们使用该变量统计ninja佯攻的次数。
        var feints = 0;

        //创建用于访问计数变量feints的方法。由于在构造函数外部的代码是无法访问feints变量的,这是通过办读形式访问该变量的常用方法。
        this.getFeints = function() {

            return feints;
        };

        //为feints变量声明一个累加方法。由于feints就私有变量在外部是无法累加的,累加过程则被限制在我们提供的方法中。
        this.feint = function() {
            feints++;
        };



    }

    // 现在开始测试,首先创建一个ninja的示例
    var ninja1 = new Ninja();
    //调用feint方法,通过该方法增加ninja的佯攻次数。
    ninja1.feint();
    

    //验证我们无法直接获取该变量值。
    assert(ninja1.feints === undefined,"Add the private data is inaccessible to us.");
    //虽然我们无法直接对feints变量赋值,但是仍然能够通过getFeints方法操作变量的值。
    assert(ninja1.getFeints()===1,"We are to access the internal feint count.");



    //当我们通过ninja构造函数创建一个新的ninja2实例时,ninja2对象则具有自己私有的feints变量。
    var ninja2 = new Ninja();
    assert(ninja2.getFeints() === 0, "the second ninja object gets its own feints variable.");

</script>
</html>

我们创建了一个Ninja构造器。通过在函数上使用关键字new时,就会创建一个新的对象实例,此时调用构造函数,将新的对象作为它的上下文,所以,函数内的this将指向新的实例化对象。
在构造器内部,我们定义了一个变量feints用于保存状态。由于javascript的作用域规则的限制,因此只能在构造内部访问该变量。为了让作用域外部的代码能够访问该变量,我们定义了访问该变量的方法getFeints。为了让作用域外部的代码能够访问私有变量,
我们定义了访问该变量的方法getFeints。该方法可以读取私有变量,但不能改写私有变量。(只读访问的方法通常称为"getter")。

 function Ninja() {
            var feints = 0;
            this.getFeints = function() {
                  return feints;
            },
            this.feint = function() {
                  feints++;
            }

      }

接下来创建增量方法feint,用于控制私有变量的值。在真实的应用程序中,该方法可能是一些业务逻辑的处理方法,但是在本例中,它只增加变量feints的值。
在构造器完成了它的使命后,我们新建ninja1实例,并调用ninja1的实例方法feint:

      var ninja1 = new Ninja();
      ninja1.feint();

通过测试显示,我们可通过闭包内部方法获取私有变量,但是不能直接访问私有变量。但有效地阻止了读私有变量不可控的修改,这与真实的面向对象语言的私有变量一样。这种情况如图
所示。

在构造器中隐藏变量,使其在外部作用域不可访问,但是可在闭包内部访问。

  • 通过变量ninja,对象实例是可见的。
  • 因为feint方法在闭包内部,因此可以访问feints。
  • 在闭包外部,我们无法访问变量feints。
    通过使用闭包,可以通过方法对ninja的状态进行维护,而不允许直接访问---这是因为闭包内部的变量可以通过闭包内的方法访问,构造器外部的代码则不能访问闭包内部的变量。
原文地址:https://www.cnblogs.com/jamal/p/14173874.html