资讯专栏INFORMATION COLUMN

闭包:私有化变量 《JavaScript高程3》 《JavaScript忍者秘籍》

vspiders / 1691人阅读

摘要:闭包闭包的特点就是内部匿名函数可以访问外部函数作用域的变量和方法变量对象。闭包的主要表现形式就是匿名函数,但是两者并不是等价的。中是没有块级作用域的,为了在中引入块级作用域,可以使用匿名函数模拟块级作用域。

在介绍闭包之前,首先解释在随后的测试实例中会使用的assert测试函数,这个方法有别于alert()测试,有很大的改进。

assert()测试方法


  
  
  
  
  
    

    用法:assert(condition, “string”); 把字符串显示在页面上,根据条件是否成立决定显示的颜色,条件为真就显示为绿色,否则为红色。


    闭包

    闭包的特点就是内部匿名函数可以访问外部函数作用域的变量和方法(变量对象)。一般来说,当函数执行完毕后, 局部活动对象(函数的变量对象)就会被销毁,内存中仅保留全局作用域(全局执行环境的变量对象)。但是闭包创建时,内部函数的作用域链中会一直引用着外部函数的活动对象,这个活动对象一直被引用而不能被回收,一直占用内存,容易造成内存泄漏。

    闭包的主要表现形式就是匿名函数,但是两者并不是等价的。闭包的常见用法就是封装一些私有变量,也就是限制这些变量的作用域。任何在函数中创建的变量都是私有变量,因为在函数外部不能访问这些变量,私有变量包括函数的参数、局部变量、在函数内部定义的其他函数。有权在外部访问私有变量的公有方法被称为特权方法第一种创建特权方法的的方式是在构造函数中定义特权方法,如下:

    function Ninjia(){
      //私有属性
      var feints = 0;
      //特权方法
      this.getFeints = function(){
        return feints;
      };
      this.feintNum = function(){
        feints++;
      };
    }
    var ninjia= new Ninjia();
    ninjia.feintNum();
    assert(ninjia.getFeints() == 1, "can accesss interal variable");//可以通过特权方法访问
    assert(ninjia.feints, "can access private variable");//无法访问
    

    可以看出,特权方法之所以能够访问构造函数中定义的所有变量和函数,根本原因在于,特权方法就是一个闭包,可以通过作用域链访问外部函数,也就是构造函数。通过构造函数定义特权方法的缺点在于使用构造函数创建自定义对象的固有弊端,那就是方法(函数对象)的重复创建。

    第二种方式是在私有作用域中定义私有变量或私有函数,同样也可以创建特权方法。
    首先介绍私有作用域。JavaScript中是没有块级作用域的,为了在JavaScript中引入块级作用域,可以使用匿名函数模拟块级作用域。为什么大费周折整出块级作用域呢?因为有了块级作用域,每个开发人员都可以在块级作用域中定义自己的变量,而不用担心会搞乱全局作用域,过多的全局作用域变量核函数会导致命名冲突。匿名函数用作块级作用域被称为私有作用域(private scope),这个匿名函数实际上就是一个闭包,它可以访问自己内部活动对象,函数执行完成即销毁,不占用内存,语法如下:

    (function () {
    //块级作用域
    })();
    

    上述代码首先将函数声明包含在圆括号中,这表示这段代码实际上是一个函数表达式,紧随其后的圆括号会立即调用这个函数。
    以下实例表明,私有作用域的变量不可由外部访问

      var outputNum = function(count){
      (function(){
        for (var i=0; i 
    

    然后介绍往私有作用域中添加私有变量和函数,同时定义特权方法。

    (function(){
    //私有属性
          var name="";
        //构造函数
          Person = function(value){
            name = value;
          };
        //构造函数原型方法-->特权方法
          Person.prototype.getName = function(){
            return name;
          }
          Person.prototype.setName = function(value){
            name = value;
          }
        })();
    
        var person1= new Person("zhang");
        alert(person1.getName());//zhang
        person1.setName("wang");
        alert(person1.getName());//wang
    
        var person2= new Person("li");
    alert(person1.getName());//li,实例间的属性共享
    

    这种方法的主要弊端在于,私有变量实际上变成了所有静态的由所有实例共享的属性,也就是说,在一个实例上调用方法改变私有变量值后,会在另一个变量上体现出来。

    闭包的使用实例: 1)Ajax回调函数中的闭包:
      jQuery("#testButton").click(function(){                          //#1
        var elem$ = jQuery("#testSubject");                            //#2
        elem$.html("Loading...");                                      //#3
        jQuery.ajax({
          url: "test.html",
          success: function(html){                                     //#4
            assert(elem$, //elem$是外部变量,匿名函数式回调函数
                  "We can see elem$, via the closure for this callback.");
            elem$.html(html);
          }
        });
      });
    
    2)计时器回调函数中的闭包:
        function animateIt(elementId){
          var elem = document.getElementById(elementId);
          var tick = 0;
          var timer = setInterval(function(){
              if (tick <100){
                elem.style.top = tick+"px";
                elem.style.left = tick+"px";
                tick++;
              }
              else{
                clearInterval(timer);
                assert(tick == 100, "Tick accessd via a closure");
                assert(elem, "elem accesse via a closure");
                assert(timer, "timer reference accessed via a closure");
              }
          }, 10);
        }
        animateIt("box");

    通过在函数内部定义变量(本例中是elem, tick, timer),并依靠闭包,可以在计时器回调函数调用的时候进行使用,这样,每个动画就有自己的私有变量(elem, tick, timer一次定义,多次使用)。如果在全局作用域中设置变量并且有多个动画需要设置,为了避免混淆,需要为每个动画设置3个变量。

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/50121.html

    相关文章

    • 闭包有化变量JavaScript高程3》 《JavaScript忍者秘籍

      摘要:闭包闭包的特点就是内部匿名函数可以访问外部函数作用域的变量和方法变量对象。闭包的主要表现形式就是匿名函数,但是两者并不是等价的。中是没有块级作用域的,为了在中引入块级作用域,可以使用匿名函数模拟块级作用域。 在介绍闭包之前,首先解释在随后的测试实例中会使用的assert测试函数,这个方法有别于alert()测试,有很大的改进。 assert()测试方法 #...

      selfimpr 评论0 收藏0
    • javascript忍者秘籍》补遗-01

      摘要:第二例这段代码是用来做将断言测试分组的,代码多了些,问题自然也更多了些。首先作者使用了自执行方法封闭了作用域,使用来指向全局对象,进而产生全局可访问的属性。没想到,久负盛名,豆瓣评分的大作,作者的光环,代码风格居然是如此的不谨慎。 第二章中 作者给了几个简单的断言例子,思路与方向是极不错的,创造JQ的大神,思想高度绝对无法让我质疑的,但是代码的功底细节,实在是让人不敢恭维。 第一例: ...

      Eric 评论0 收藏0
    • JavaScript学习之路 — 函数、闭包与原型链

      摘要:全局的函数第个对象第个对象作为构造器进行调用也就是利用运算符进行调用。与操作的共同使用只有通过操作产生的对象,可以使用构造器函数原型链上的内容,否则对象只能使用自己原型链上的内容。 今天这个话题是因为这几天看了《JavaScript忍者秘籍》,感觉这本书把这几个内容讲的蛮透彻了,特撰本文,以便日后翻阅。(应该都会以知识点的形式给出吧。) 函数 1.【基本类型】 JavaScript中函...

      klivitamJ 评论0 收藏0
    • 第一章无处不在的JavaScriptJavascript忍者秘籍2阅读笔记】

      摘要:无处不在的理解语言与其他主流语言相比,函数式语言的血统更多一些。函数式语言一类程序设计语言,是一种非冯诺伊曼式的程序设计语言。函数式语言主要成分是原始函数,定义函数和函数型。性能分析内置对象上的和方法。 无处不在的JavaScript 理解JavaScript语言 与其他主流语言相比,JavaScript函数式语言的血统更多一些。 函数式语言一类程序设计语言,是一种非冯.诺伊曼式的程序...

      yck 评论0 收藏0
    • 浅谈JavaScript闭包

      摘要:但是函数返回了内部函数,内部函数会随时访问变量所以垃圾回收机制是不会回收函数的内部作用域的,这就是闭包的含义。也就是函数在定义的词法作用域以外的地方被调用,闭包使得函数可以继续访问定义时的词法作用域。   初学JavaScript闭包时,闭包这个概念在我眼里及其的神秘,也不知道这个东西在讲什么,尤其某些地方的闭包概念定义的非常抽象,属于那种本来你可能明白这个概念,看了反而又把你给绕糊涂...

      hsluoyz 评论0 收藏0

    发表评论

    0条评论

    最新活动
    阅读需要支付1元查看
    <