JavaScript高级之-------闭包的概念及其应用

主要内容:
     1) 什么是闭包
     2) 闭包使用的一般模式
     3) 闭包都能做些什么

     本文是我的JavaScript高级这个系列中的第二篇文章. 在这个系列中,我计划分析说明
一下JavaScript中的一些常用的而又神秘的高级内容,包括:作用域链、闭包、函数调用形
式、面向对象等内容. 本文就闭包做个说明.
     一说到JavaScript,就能想到闭包是个神奇的东西. 到底闭包是什么,以及怎么使用?
今天我们来分析一下!
     同样,这个也属于JavaScript的高级的部分,对于JavaScript而言基础非常重要,对于
基本语法,动态语言的基本特征希望不太了解的朋友,找本书或一些系统点的资料看看. 这
样有助于对后文的理解. 当然,也可以到http://net.itcast.cn中去下载一下东西看看.
     下面正式进入今天的主题.

一、何为闭包
     "闭包"这个词并非是JavaScript特有的,实际上闭包是一个特有的概念. 至于概念本身
我不过多介绍,百度一下什么都有. 我主要说说JavaScript中闭包是什么.

     在JavaScript中闭包就是函数

     闭包就是函数,这个概念似乎感觉有点迷惑. 实际上很简单,闭包就是一个封闭包裹的
范围. 前文咱们提到过,函数可以限定变量的作用域. 一个变量在函数内部声明,那么在函
数外部是无法访问的. 那么这个就是一个封闭的范围. 广义上说就是一个闭包了!
     那么这个样子其实没有什么意义. 因为没有什么特别的地方, 但是如果函数中又定义了
函数,并将这个函数以返回值的形式返回,那么,在JavaScript中"子域访问父域"的规则就
会打破了. 因为这个时候,在函数外就可以访问函数内的变量. 看下面代码:

var func = function() {
     var num = 10;
     return function() {
          alert(num);
     };
};
var foo = func();
foo();

这段代码中,函数foo是0级链,而变量num是在1级链中,这个时候,0级链的函数就访问了1级
链中的变量num,这段代码运行结果是打印出10. 这样就实现了JavaScript中的闭包.

     小结一下,JavaScript中的闭包就是在函数中定义变量,然后通过返回值,将可以访问这
个变量的函数返回,这样在函数外就可以访问函数内的变量了. 这样就形成了闭包.


二、闭包的使用案例及其说明

     闭包的案例非常的多. 在JavaScript中,使用闭包就像C语言中使用指针一样. 其基本语法
简单,但是使用灵活多变,使用其灵活的语法与特征就能实现许多非常强大的功能. 在此不能阐
述闭包的所有用法,但是对于刚刚接触闭包的朋友,下面的案例足够理解一段时间了.

2.1 模拟私有成员
    
     这个案例是JavaScript实现面向对象的基础. 看下面代码

var Person = function(name, age, gender) {
     return {
          get_name :      function() {
                              return name;
                         },
          set_name :     function(value) {
                              name = value;
                         },
          get_age :     function(){
                              return age;
                         },
          get_gender :     function(){
                         return gender;
                    }
     };
};

这段代码就是一个函数,函数带有三个参数,也就是说在函数内部有三个局部变量,分别表示姓
名(name)、年龄(age)和性别(gender). 然后在返回值中,返回一个对象,该对象提供四个方法.
分别给年龄提供读写方法,给性别与年龄提供读取的方法. 这四个函数都是这个函数的子域. 因
此返回的这个对象就可以直接访问这三个变量. 但是有了读写的访问权限的限制.

2.2 Fibonacci数列

     Fibonacci数列就是:1, 1, 2, 3, 5, 8, 13, ...
     这个案例是面试题中经常考到的案例,也算是具有代表性的算法题. 看下面代码:

// 为了简单就不做n的判断处理了
var Fib = (function() {
     var fibArr = [1,1];
     return function( n ) {
          var res = fibArr[n];
          if(res) {
               return res;
          } else {
               res = arguments.callee(n - 1) + arguments.callee(n - 2);
               fibArr.push(res);
               return res;
          }
     };
})();

     这个案例一般传统的做法就是使用递归,但是递归的性能问题十分可怕,如果大家有兴趣可以
计算一下这个数列的第20项结果是多少,并统计一下这个函数递归调用了多少次. 如下面代码

var count = 0;
var fib = function(n) {
     count++;
     // 为了简单就不做n的判断处理了
     if(n == 0 || n == 1) return 1;
     return fib(n-1) + fib(n-2);
};
var res = fib(20);
alert("fib(20)的结果为:" + res + ", 函数调用了 " + count + " 次");

     然后再用新方法,计算同样的结果,并统计一下次数.
    
var count = 0;
// 为了简单就不做n的判断处理了
var Fib = (function() {
     var fibArr = [1,1];
     return function( n ) {
          count++;
          var res = fibArr[n];
          if(res) {
               return res;
          } else {
               res = arguments.callee(n - 1) + arguments.callee(n - 2);
               fibArr.push(res);
               return res;
          }
     };
})();
var res = Fib(20);
alert("Fib(20)的结果为:" + res + ", 函数调用了 " + count + " 次");

这个结果,我不在这里揭晓,请大家自己下去运行看看.

     下面分析一下这段新方法的代码. 在这段代码中,绑定在Fib中的函数,实际上是后面函数运
行的返回结果. 后面这个函数有一个私有变量,是一个数组. 保存着第0项和第1项数组的值. 然后
返回一个函数. 在调用 Fib(20) 的时候就是在执行这个被返回的函数.
     这个函数中,首先访问数组的第n项值,如果数组中有这个数据,就直接返回,否则实现递归
计算这个值,并将值加到数组中,最后返回计算的结果. 在JavaScript中,递归使用
arguments.callee()表示当前调用函数(即递归函数).
     那么这么做最直接的结果是,存在一个缓存,将计算得到的结果保存在缓存中,并且实现所有
的计算只计算一次,那么可以大大的提高性能.


2.3 html字符串案例

     这个是许多js库使用的办法,在很多js库中需要使用正则表达式处理一些数据,而如果每次执
行都在方法中保存需要处理匹配的字符串,那么会大量的消耗内存,影响性能. 因此可以将重复使
用的表达式都保存在闭包中,每次使用都是访问的这个字符串. 例如:
    
String.prototype.deentityify = function() {
     var entity = {
          lt          :     '<',
          gt          :     '>'
     };
     return function() {
          return this.replace(/&([^;]+);/g, function(a,b) {
               var r = entity[b];
               return typeof r === 'string' ? r : a;
          });
     };
}();

这段代码会将任何一个字符串中的 &lt; 和 &gt; 都替换成尖括号<和>,对于页面html代码的复制
非常好用.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值